Skip to content

Commit

Permalink
Tables builder changes (#21368)
Browse files Browse the repository at this point in the history
* Renamed UpdateMode to TableEntityUpdateMode.

* Moved Options classes to a separate 'options' package from 'models'.

* Renamed TablesServiceVersion to TableServiceVersion.

* Made TableItem, TableClient, TableServiceClient, TableServiceAsyncClient, TableClientBuilder and TableServiceClientBuilder final.

* Renamed the following methods:
- TableClient, TableAsyncClient
    - getTableUrl() -> getTableEndpoint()
    - getApiVersion() -> getServiceVersion()
- TableServiceClient, TableServiceAsyncClient
    - getServiceUrl() -> getServiceEndpoint()
    - getApiVersion() -> getServiceVersion()

* Renamed addProperties() to setProperties(). Also made setProperties() replace the contents of properties map with those of the argument, instead of adding them to the existing properties.

* Fixed embedme errors.

* Moved back options classes to the 'models' package.

* Replaced retryOptions(RequestRetryOptions) with retryPolicy(RetryPolicy) in TableClientBuilder and TableServiceClientBuilder.

* Removed TableSharedKeyCredential in favor of using Azure Core's AzureNamedKeyCredential. Replaced TableSharedKeyCredentialPolicy with AzureNamedKeyCredentialPolicy.

* Applied PR feedback.
  • Loading branch information
vcolin7 authored May 14, 2021
1 parent a6a3a52 commit 0c8110a
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 256 deletions.
34 changes: 17 additions & 17 deletions sdk/tables/azure-data-tables/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,19 +149,19 @@ Common uses of the Tables service include:
#### Authenticate with a connection string
To use a connection string to authorize your client, call the builder's `connectionString` method with your connection string.

<!-- embedme src/samples/java/ReadmeSamples.java#L33-L35 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L34-L36 -->
```java
TableServiceClient tableServiceClient = new TableServiceClientBuilder()
.connectionString("<your-connection-string>")
.buildClient();
```

#### Authenticate with a Shared Key
To use a Shared Key to authorize your client, create an instance of `TablesSharedKeyCredential` with your account name and access key. Call the builder's `endpoint` method with your account URL and the `credential` method with the `TablesSharedKeyCredential` object you created.
#### Authenticate with a Named Key
To use a Named Key to authorize your client, create an instance of `AzureNamedKeyCredential` with your account name and access key. Call the builder's `endpoint` method with your account URL and the `credential` method with the `AzureNamedKeyCredential` object you created.

<!-- embedme src/samples/java/ReadmeSamples.java#L42-L46 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L43-L47 -->
```java
TablesSharedKeyCredential credential = new TablesSharedKeyCredential("<your-account-name>", "<account-access-key>");
AzureNamedKeyCredential credential = new AzureNamedKeyCredential("<your-account-name>", "<account-access-key>");
TableServiceClient tableServiceClient = new TableServiceClientBuilder()
.endpoint("<your-table-account-url>")
.credential(credential)
Expand All @@ -171,7 +171,7 @@ TableServiceClient tableServiceClient = new TableServiceClientBuilder()
#### Authenticate with a Shared Access Signature (SAS)
To use a SAS to authorize your client, call the builder's `endpoint` method with your account URL and the `sasToken` method with your SAS.

<!-- embedme src/samples/java/ReadmeSamples.java#L53-L56 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L54-L57 -->
```java
TableServiceClient tableServiceClient = new TableServiceClientBuilder()
.endpoint("<your-table-account-url>")
Expand All @@ -184,7 +184,7 @@ TableServiceClient tableServiceClient = new TableServiceClientBuilder()
#### Construct a `TableServiceClient`
Construct a `TableServiceClient` by creating an instance of `TableServiceClientBuilder` and then calling the builder's `buildClient` or `buildAsyncClient` methods.

<!-- embedme src/samples/java/ReadmeSamples.java#L63-L65 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L64-L66 -->
```java
TableServiceClient tableServiceClient = new TableServiceClientBuilder()
.connectionString("<your-connection-string>") // or use any of the other authentication methods
Expand All @@ -194,22 +194,22 @@ TableServiceClient tableServiceClient = new TableServiceClientBuilder()
#### Create a table
Create a table by calling the `TableServiceClient`'s `createTable` method. An exception will be thrown if a table with the provided name exists.

<!-- embedme src/samples/java/ReadmeSamples.java#L74-L74 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L75-L75 -->
```java
tableServiceClient.createTable(tableName);
```

Alternatively, you can call the `createTableIfNotExists` method which will create the table only if no such table exists, and does not throw an exception.

<!-- embedme src/samples/java/ReadmeSamples.java#L81-L81 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L82-L82 -->
```java
tableServiceClient.createTableIfNotExists(tableName);
```

#### List tables
List or query the set of existing tables by calling the `TableServiceClient`'s `listTables` method, optionally passing in a `ListTablesOptions` instance to filter or limit the query results. See [Supported Query Options][query_options] for details about supported query options.

<!-- embedme src/samples/java/ReadmeSamples.java#L88-L93 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L89-L94 -->
```java
ListTablesOptions options = new ListTablesOptions()
.setFilter(String.format("TableName eq '%s'", tableName));
Expand All @@ -222,7 +222,7 @@ for (TableItem tableItem : tableServiceClient.listTables(options)) {
#### Delete a table
Delete a table by calling the `TableServiceClient`'s `deleteTable` method. An exception will be thrown if no table with the provided name exists.

<!-- embedme src/samples/java/ReadmeSamples.java#L100-L100 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L101-L101 -->
```java
tableServiceClient.deleteTable(tableName);
```
Expand All @@ -232,7 +232,7 @@ tableServiceClient.deleteTable(tableName);
#### Construct a `TableClient`
Construct a `TableClient` by creating an instance of `TableClientBuilder`, calling the builder's `tableName` method with the name of the table, and then calling its `buildClient` or `buildAsyncClient` methods.

<!-- embedme src/samples/java/ReadmeSamples.java#L107-L110 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L108-L111 -->
```java
TableClient tableClient = new TableClientBuilder()
.connectionString("<your-connection-string>") // or use any of the other authentication methods
Expand All @@ -242,15 +242,15 @@ TableClient tableClient = new TableClientBuilder()

Alternatively, a `TableClient` can be retrieved from an existing `TableServiceClient` by calling its `getTableClient` method.

<!-- embedme src/samples/java/ReadmeSamples.java#L117-L117 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L118-L118 -->
```java
TableClient tableClient = tableServiceClient.getTableClient(tableName);
```

#### Create an entity
Create a new `TableEntity` instance, providing the partition key and row key of the entity to create, optionally adding properties to the created object. Then pass the object to the `TableClient`'s `createEntity` method. An exception will be thrown if an entity with the provided partition key and row key exists within the table.

<!-- embedme src/samples/java/ReadmeSamples.java#L126-L131 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L127-L132 -->
```java
TableEntity entity = new TableEntity(partitionKey, rowKey)
.addProperty("Product", "Marker Set")
Expand All @@ -263,7 +263,7 @@ tableClient.createEntity(entity);
#### List entities
List or query the set of entities within the table by calling the `TableClient`'s `listEntities` method, optionally passing in a `ListEntitiesOptions` instance to filter, select, or limit the query results. See [Supported Query Options][query_options] for details about supported query options.

<!-- embedme src/samples/java/ReadmeSamples.java#L138-L145 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L139-L146 -->
```java
ListEntitiesOptions options = new ListEntitiesOptions()
.setFilter(String.format("PartitionKey eq '%s'", partitionKey))
Expand All @@ -278,7 +278,7 @@ for (TableEntity entity : tableClient.listEntities(options)) {
#### Delete an entity
Delete an entity by calling the `TableClient`'s `deleteEntity` method. An exception will be thrown if no entity with the provided partition key and row key exists.

<!-- embedme src/samples/java/ReadmeSamples.java#L152-L152 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L153-L153 -->
```java
tableClient.deleteEntity(partitionKey, rowKey);
```
Expand All @@ -290,7 +290,7 @@ When you interact with Tables service using the Azure Tables library for Java, e

For example, if you try to create a table that already exists, a `409` error is returned, indicating "Conflict".

<!-- embedme src/samples/java/ReadmeSamples.java#L159-L167 -->
<!-- embedme src/samples/java/ReadmeSamples.java#L160-L168 -->
```java
// Create the table if it doesn't already exist.
tableServiceClient.createTableIfNotExists(tableName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

package com.azure.data.tables;

import com.azure.core.credential.AzureNamedKeyCredential;
import com.azure.core.credential.AzureSasCredential;
import com.azure.core.credential.TokenCredential;
import com.azure.core.http.HttpClient;
import com.azure.core.http.HttpHeader;
import com.azure.core.http.HttpHeaders;
Expand All @@ -13,25 +13,23 @@
import com.azure.core.http.policy.AddDatePolicy;
import com.azure.core.http.policy.AddHeadersPolicy;
import com.azure.core.http.policy.AzureSasCredentialPolicy;
import com.azure.core.http.policy.BearerTokenAuthenticationPolicy;
import com.azure.core.http.policy.HttpLogOptions;
import com.azure.core.http.policy.HttpLoggingPolicy;
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.core.http.policy.HttpPolicyProviders;
import com.azure.core.http.policy.RequestIdPolicy;
import com.azure.core.http.policy.RetryPolicy;
import com.azure.core.http.policy.UserAgentPolicy;
import com.azure.core.util.ClientOptions;
import com.azure.core.util.Configuration;
import com.azure.core.util.CoreUtils;
import com.azure.core.util.UrlBuilder;
import com.azure.core.util.logging.ClientLogger;
import com.azure.data.tables.implementation.CosmosPatchTransformPolicy;
import com.azure.data.tables.implementation.NullHttpClient;
import com.azure.storage.common.implementation.Constants;
import com.azure.storage.common.policy.RequestRetryOptions;
import com.azure.storage.common.policy.RequestRetryPolicy;
import com.azure.storage.common.policy.ResponseValidationPolicyBuilder;
import com.azure.storage.common.policy.ScrubEtagPolicy;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand All @@ -47,16 +45,16 @@ final class BuilderHelper {
private static final String COSMOS_ENDPOINT_SUFFIX = "cosmos.azure.com";

static HttpPipeline buildPipeline(
TablesSharedKeyCredential tablesSharedKeyCredential,
TokenCredential tokenCredential, AzureSasCredential azureSasCredential, String sasToken,
String endpoint, RequestRetryOptions retryOptions, HttpLogOptions logOptions, ClientOptions clientOptions,
AzureNamedKeyCredential azureNamedKeyCredential, AzureSasCredential azureSasCredential, String sasToken,
String endpoint, RetryPolicy retryPolicy, HttpLogOptions logOptions, ClientOptions clientOptions,
HttpClient httpClient, List<HttpPipelinePolicy> perCallAdditionalPolicies,
List<HttpPipelinePolicy> perRetryAdditionalPolicies, Configuration configuration, ClientLogger logger) {

configuration = (configuration == null) ? Configuration.getGlobalConfiguration() : configuration;
retryPolicy = (retryPolicy == null) ? new RetryPolicy() : retryPolicy;
logOptions = (logOptions == null) ? new HttpLogOptions() : logOptions;

validateSingleCredentialIsPresent(
tablesSharedKeyCredential, tokenCredential, azureSasCredential, sasToken, logger);
validateSingleCredentialIsPresent(azureNamedKeyCredential, azureSasCredential, sasToken, logger);

// Closest to API goes first, closest to wire goes last.
List<HttpPipelinePolicy> policies = new ArrayList<>();
Expand Down Expand Up @@ -84,19 +82,12 @@ static HttpPipeline buildPipeline(
HttpPolicyProviders.addBeforeRetryPolicies(policies);

// Add retry policy.
policies.add(new RequestRetryPolicy(retryOptions));
policies.add(retryPolicy);

policies.add(new AddDatePolicy());
HttpPipelinePolicy credentialPolicy;
if (tablesSharedKeyCredential != null) {
credentialPolicy = new TablesSharedKeyCredentialPolicy(tablesSharedKeyCredential);
} else if (tokenCredential != null) {
UrlBuilder endpointParts = UrlBuilder.parse(endpoint);
if (!endpointParts.getScheme().equals(Constants.HTTPS)) {
throw logger.logExceptionAsError(new IllegalArgumentException(String.format(
"HTTPS is required when using a %s credential.", tokenCredential.getClass().getName())));
}
credentialPolicy = new BearerTokenAuthenticationPolicy(tokenCredential, getBearerTokenScope(endpointParts));
if (azureNamedKeyCredential != null) {
credentialPolicy = new TableAzureNamedKeyCredentialPolicy(azureNamedKeyCredential);
} else if (azureSasCredential != null) {
credentialPolicy = new AzureSasCredentialPolicy(azureSasCredential, false);
} else if (sasToken != null) {
Expand Down Expand Up @@ -139,11 +130,10 @@ static HttpPipeline buildNullClientPipeline() {
.build();
}

private static void validateSingleCredentialIsPresent(
TablesSharedKeyCredential storageSharedKeyCredential,
TokenCredential tokenCredential, AzureSasCredential azureSasCredential, String sasToken, ClientLogger logger) {
List<Object> usedCredentials = Stream.of(
storageSharedKeyCredential, tokenCredential, azureSasCredential, sasToken)
private static void validateSingleCredentialIsPresent(AzureNamedKeyCredential azureNamedKeyCredential,
AzureSasCredential azureSasCredential, String sasToken,
ClientLogger logger) {
List<Object> usedCredentials = Stream.of(azureNamedKeyCredential, azureSasCredential, sasToken)
.filter(Objects::nonNull).collect(Collectors.toList());
if (usedCredentials.size() > 1) {
throw logger.logExceptionAsError(new IllegalStateException(
Expand All @@ -154,20 +144,6 @@ private static void validateSingleCredentialIsPresent(
}
}

/**
* @param endpoint The endpoint passed by the customer.
* @return The bearer token scope for the primary endpoint for the account. It may be the same endpoint passed if it
* is already a primary or it may have had "-secondary" stripped from the end of the account name.
*/
private static String getBearerTokenScope(UrlBuilder endpoint) {
String[] hostParts = endpoint.getHost().split("\\.");
if (hostParts[0].endsWith("-secondary")) {
hostParts[0] = hostParts[0].substring(0, hostParts[0].length() - 10); // Strip off the '-secondary' suffix
endpoint.setHost(String.join(".", hostParts));
}
return String.format("%s/.default", endpoint.toString());
}

/*
* Creates a {@link ResponseValidationPolicyBuilder.ResponseValidationPolicy} used to validate response data from
* the service.
Expand Down
Loading

0 comments on commit 0c8110a

Please sign in to comment.