Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tables list/get access policies changes #22161

Merged
merged 9 commits into from
Jun 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,6 @@ static HttpPipeline buildPipeline(
httpHeaderList.add(new HttpHeader(header.getName(), header.getValue())));
}

// TODO: Remove the Accept header after making sure the JacksonAdapter can handle not setting such value.
policies.add(new AddHeadersPolicy(new HttpHeaders(httpHeaderList).set("Accept", "application/json")));

// Add per call additional policies.
policies.addAll(perCallAdditionalPolicies);
HttpPolicyProviders.addBeforeRetryPolicies(policies);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import com.azure.core.http.HttpRequest;
import com.azure.core.http.rest.PagedFlux;
import com.azure.core.http.rest.PagedResponse;
import com.azure.core.http.rest.PagedResponseBase;
import com.azure.core.http.rest.Response;
import com.azure.core.http.rest.SimpleResponse;
import com.azure.core.util.Context;
Expand Down Expand Up @@ -42,6 +41,7 @@
import com.azure.data.tables.implementation.models.TransactionalBatchResponse;
import com.azure.data.tables.implementation.models.TransactionalBatchSubRequest;
import com.azure.data.tables.models.ListEntitiesOptions;
import com.azure.data.tables.models.TableAccessPolicies;
import com.azure.data.tables.models.TableAccessPolicy;
import com.azure.data.tables.models.TableEntity;
import com.azure.data.tables.models.TableEntityUpdateMode;
Expand All @@ -57,17 +57,15 @@
import reactor.core.publisher.Mono;

import java.net.URI;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.azure.core.util.CoreUtils.isNullOrEmpty;
import static com.azure.core.util.FluxUtil.fluxContext;
import static com.azure.core.util.FluxUtil.monoError;
import static com.azure.core.util.FluxUtil.pagedFluxError;
import static com.azure.core.util.FluxUtil.withContext;
import static com.azure.data.tables.implementation.TableUtils.swallowExceptionForStatusCode;
import static com.azure.data.tables.implementation.TableUtils.toTableServiceError;
Expand Down Expand Up @@ -845,45 +843,55 @@ <T extends TableEntity> Mono<Response<T>> getEntityWithResponse(String partition
* Retrieves details about any stored access policies specified on the table that may be used with Shared Access
* Signatures.
*
* @return A paged reactive result containing the HTTP response and the table's
* {@link TableSignedIdentifier access policies}.
* @return A reactive result containing the table's {@link TableAccessPolicies access policies}.
*/
@ServiceMethod(returns = ReturnType.COLLECTION)
public PagedFlux<TableSignedIdentifier> listAccessPolicies() {
return (PagedFlux<TableSignedIdentifier>) fluxContext(this::listAccessPolicies);
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<TableAccessPolicies> getAccessPolicies() {
return withContext(context -> getAccessPoliciesWithResponse(context)
.flatMap(response -> Mono.justOrEmpty(response.getValue())));
}

/**
* Retrieves details about any stored access policies specified on the table that may be used with Shared Access
* Signatures.
*
* @return A reactive result containing an HTTP response that contains the table's
* {@link TableAccessPolicies access policies}.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<Response<TableAccessPolicies>> getAccessPoliciesWithResponse() {
return withContext(this::getAccessPoliciesWithResponse);
}

PagedFlux<TableSignedIdentifier> listAccessPolicies(Context context) {
Mono<Response<TableAccessPolicies>> getAccessPoliciesWithResponse(Context context) {
context = context == null ? Context.NONE : context;

try {
Context finalContext = context;
Function<String, Mono<PagedResponse<TableSignedIdentifier>>> retriever =
marker ->
tablesImplementation.getTables()
.getAccessPolicyWithResponseAsync(tableName, null, null, finalContext)
.map(response -> new PagedResponseBase<>(response.getRequest(),
response.getStatusCode(),
response.getHeaders(),
response.getValue().stream()
.map(this::toTableSignedIdentifier)
.collect(Collectors.toList()),
null,
response.getDeserializedHeaders()));

return new PagedFlux<>(() -> retriever.apply(null), retriever);
return tablesImplementation.getTables()
.getAccessPolicyWithResponseAsync(tableName, null, null, context)
.map(response -> new SimpleResponse<>(response,
new TableAccessPolicies(response.getValue() == null ? null : response.getValue().stream()
.map(this::toTableSignedIdentifier)
.collect(Collectors.toList()))));
} catch (RuntimeException e) {
return pagedFluxError(logger, e);
return monoError(logger, e);
}
}

private TableSignedIdentifier toTableSignedIdentifier(SignedIdentifier signedIdentifier) {
return new TableSignedIdentifier()
.setId(signedIdentifier.getId())
if (signedIdentifier == null) {
return null;
}

return new TableSignedIdentifier(signedIdentifier.getId())
.setAccessPolicy(toTableAccessPolicy(signedIdentifier.getAccessPolicy()));
}

private TableAccessPolicy toTableAccessPolicy(AccessPolicy accessPolicy) {
if (accessPolicy == null) {
return null;
}

return new TableAccessPolicy()
.setExpiresOn(accessPolicy.getExpiry())
.setStartsOn(accessPolicy.getStart())
Expand Down Expand Up @@ -918,24 +926,66 @@ public Mono<Response<Void>> setAccessPoliciesWithResponse(List<TableSignedIdenti
Mono<Response<Void>> setAccessPoliciesWithResponse(List<TableSignedIdentifier> tableSignedIdentifiers,
Context context) {
context = context == null ? Context.NONE : context;
List<SignedIdentifier> signedIdentifiers = null;

/*
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 (tableSignedIdentifiers != null) {
signedIdentifiers = tableSignedIdentifiers.stream()
.map(tableSignedIdentifier -> {
SignedIdentifier signedIdentifier = toSignedIdentifier(tableSignedIdentifier);

if (signedIdentifier != null) {
if (signedIdentifier.getAccessPolicy() != null
&& signedIdentifier.getAccessPolicy().getStart() != null) {

signedIdentifier.getAccessPolicy()
.setStart(signedIdentifier.getAccessPolicy()
.getStart().truncatedTo(ChronoUnit.SECONDS));
}

if (signedIdentifier.getAccessPolicy() != null
&& signedIdentifier.getAccessPolicy().getExpiry() != null) {

signedIdentifier.getAccessPolicy()
.setExpiry(signedIdentifier.getAccessPolicy()
.getExpiry().truncatedTo(ChronoUnit.SECONDS));
}
}

return signedIdentifier;
})
.collect(Collectors.toList());
}

try {
return tablesImplementation.getTables()
.setAccessPolicyWithResponseAsync(tableName, null, null,
tableSignedIdentifiers.stream().map(this::toSignedIdentifier).collect(Collectors.toList()), context)
.setAccessPolicyWithResponseAsync(tableName, null, null, signedIdentifiers, context)
.map(response -> new SimpleResponse<>(response, response.getValue()));
} catch (RuntimeException e) {
return monoError(logger, e);
}
}

private SignedIdentifier toSignedIdentifier(TableSignedIdentifier tableSignedIdentifier) {
if (tableSignedIdentifier == null) {
return null;
}

return new SignedIdentifier()
.setId(tableSignedIdentifier.getId())
.setAccessPolicy(toAccessPolicy(tableSignedIdentifier.getAccessPolicy()));
}

private AccessPolicy toAccessPolicy(TableAccessPolicy tableAccessPolicy) {
if (tableAccessPolicy == null) {
return null;
}

return new AccessPolicy()
.setExpiry(tableAccessPolicy.getExpiresOn())
.setStart(tableAccessPolicy.getStartsOn())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.azure.core.http.rest.Response;
import com.azure.core.util.Context;
import com.azure.data.tables.models.ListEntitiesOptions;
import com.azure.data.tables.models.TableAccessPolicies;
import com.azure.data.tables.models.TableEntity;
import com.azure.data.tables.models.TableEntityUpdateMode;
import com.azure.data.tables.models.TableItem;
Expand Down Expand Up @@ -411,12 +412,11 @@ public Response<TableEntity> getEntityWithResponse(String partitionKey, String r
* Retrieves details about any stored access policies specified on the table that may be used with Shared Access
* Signatures.
*
* @return A reactive result containing the HTTP response and the table's
* {@link TableSignedIdentifier access policies}.
* @return The table's {@link TableAccessPolicies access policies}.
*/
@ServiceMethod(returns = ReturnType.COLLECTION)
public PagedIterable<TableSignedIdentifier> listAccessPolicies() {
return new PagedIterable<>(client.listAccessPolicies());
@ServiceMethod(returns = ReturnType.SINGLE)
public TableAccessPolicies getAccessPolicies() {
return client.getAccessPolicies().block();
}

/**
Expand All @@ -426,12 +426,11 @@ public PagedIterable<TableSignedIdentifier> listAccessPolicies() {
* @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised.
* @param context Additional context that is passed through the HTTP pipeline during the service call.
*
* @return A reactive result containing the HTTP response and the table's
* {@link TableSignedIdentifier access policies}.
* @return An HTTP response containing the table's {@link TableAccessPolicies access policies}.
*/
@ServiceMethod(returns = ReturnType.COLLECTION)
public PagedIterable<TableSignedIdentifier> listAccessPolicies(Duration timeout, Context context) {
return new PagedIterable<>(applyOptionalTimeout(client.listAccessPolicies(context), timeout));
@ServiceMethod(returns = ReturnType.SINGLE)
public Response<TableAccessPolicies> getAccessPoliciesWithResponse(Duration timeout, Context context) {
return blockWithOptionalTimeout(client.getAccessPoliciesWithResponse(context), timeout);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,6 @@ public Mono<Void> setProperties(TableServiceProperties tableServiceProperties) {
return this.setPropertiesWithResponse(tableServiceProperties).flatMap(FluxUtil::toMono);
}


/**
* Sets the properties of an account's Table service, including properties for Analytics and CORS (Cross-Origin
* Resource Sharing) rules.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.azure.data.tables.implementation.models.QueryOptions;
import com.azure.data.tables.implementation.models.ResponseFormat;
import com.azure.data.tables.implementation.models.SignedIdentifier;
import com.azure.data.tables.implementation.models.SignedIdentifiersWrapper;
import com.azure.data.tables.implementation.models.TableProperties;
import com.azure.data.tables.implementation.models.TableServiceErrorException;
import com.azure.data.tables.implementation.models.TablesCreateResponse;
Expand Down Expand Up @@ -238,7 +239,7 @@ Mono<TablesSetAccessPolicyResponse> setAccessPolicy(
@HeaderParam("x-ms-client-request-id") String requestId,
@PathParam("table") String table,
@QueryParam("comp") String comp,
@BodyParam("application/xml") List<SignedIdentifier> tableAcl,
@BodyParam("application/xml") SignedIdentifiersWrapper tableAcl,
@HeaderParam("Accept") String accept,
Context context);
}
Expand Down Expand Up @@ -725,14 +726,17 @@ public Mono<TablesSetAccessPolicyResponse> setAccessPolicyWithResponseAsync(
String table, Integer timeout, String requestId, List<SignedIdentifier> tableAcl, Context context) {
final String comp = "acl";
final String accept = "application/xml";

SignedIdentifiersWrapper tableAclConverted = new SignedIdentifiersWrapper(tableAcl);

return service.setAccessPolicy(
this.client.getUrl(),
timeout,
this.client.getVersion(),
requestId,
table,
comp,
tableAcl,
tableAclConverted,
accept,
context);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.data.tables.implementation.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.List;

/** A wrapper around List&lt;SignedIdentifier&gt; which provides top-level metadata for serialization. */
@JacksonXmlRootElement(localName = "SignedIdentifiers")
public final class SignedIdentifiersWrapper {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an issue to get the code generator working correctly to generate this type?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I don't know how to get it to do that, so I added the class manually and was looking to add a transform later (once I learn enough about autorest).

@JacksonXmlProperty(localName = "SignedIdentifier")
private final List<SignedIdentifier> signedIdentifiers;

/**
* Creates an instance of SignedIdentifiersWrapper.
*
* @param signedIdentifiers the list.
*/
@JsonCreator
public SignedIdentifiersWrapper(@JsonProperty("SignedIdentifier") List<SignedIdentifier> signedIdentifiers) {
this.signedIdentifiers = signedIdentifiers;
}

/**
* Get the List&lt;BlobSignedIdentifier&gt; contained in this wrapper.
*
* @return the List&lt;BlobSignedIdentifier&gt;.
*/
public List<SignedIdentifier> items() {
return signedIdentifiers;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.data.tables.models;

import com.azure.core.annotation.Immutable;

import java.util.List;

/**
* This class contains values which correlate to the access polices set for a specific table.
*/
@Immutable
public final class TableAccessPolicies {
private final List<TableSignedIdentifier> identifiers;

/**
* Constructs a {@link TableAccessPolicies}.
*
* @param identifiers {@link TableSignedIdentifier TableSignedIdentifiers} associated with the table.
*/
public TableAccessPolicies(List<TableSignedIdentifier> identifiers) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does Tables support public access as Blobs does?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean like when you have a SAS for a given blob? Unfortunately I don't know that right now.

this.identifiers = identifiers;
}

/**
* @return the {@link TableSignedIdentifier TableSignedIdentifiers} associated with the table.
*/
public List<TableSignedIdentifier> getIdentifiers() {
return this.identifiers;
}
}
Loading