From 3875f7d39f581b84872522d80a6991f8623803cf Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Mon, 27 Jan 2020 11:00:36 -0800 Subject: [PATCH 1/8] Recreate HMAC algorithm every time. (#7736) --- .../EventHubSharedKeyCredential.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubSharedKeyCredential.java b/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubSharedKeyCredential.java index e69334cb6584..03e1df34b68f 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubSharedKeyCredential.java +++ b/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubSharedKeyCredential.java @@ -49,8 +49,8 @@ public class EventHubSharedKeyCredential implements TokenCredential { private final ClientLogger logger = new ClientLogger(EventHubSharedKeyCredential.class); private final String policyName; - private final Mac hmac; private final Duration tokenValidity; + private final SecretKeySpec secretKeySpec; /** * Creates an instance that authorizes using the {@code policyName} and {@code sharedAccessKey}. @@ -96,21 +96,8 @@ public EventHubSharedKeyCredential(String policyName, String sharedAccessKey, Du throw new IllegalArgumentException("'tokenTimeToLive' has to positive and in the order-of seconds"); } - try { - hmac = Mac.getInstance(HASH_ALGORITHM); - } catch (NoSuchAlgorithmException e) { - throw logger.logExceptionAsError(new UnsupportedOperationException( - String.format("Unable to create hashing algorithm '%s'", HASH_ALGORITHM), e)); - } - final byte[] sasKeyBytes = sharedAccessKey.getBytes(UTF_8); - final SecretKeySpec finalKey = new SecretKeySpec(sasKeyBytes, HASH_ALGORITHM); - try { - hmac.init(finalKey); - } catch (InvalidKeyException e) { - throw logger.logExceptionAsError(new IllegalArgumentException( - "'sharedAccessKey' is an invalid value for the hashing algorithm.", e)); - } + secretKeySpec = new SecretKeySpec(sasKeyBytes, HASH_ALGORITHM); } /** @@ -137,6 +124,18 @@ private AccessToken generateSharedAccessSignature(final String resource) throws throw logger.logExceptionAsError(new IllegalArgumentException("resource cannot be empty")); } + final Mac hmac; + try { + hmac = Mac.getInstance(HASH_ALGORITHM); + hmac.init(secretKeySpec); + } catch (NoSuchAlgorithmException e) { + throw logger.logExceptionAsError(new UnsupportedOperationException( + String.format("Unable to create hashing algorithm '%s'", HASH_ALGORITHM), e)); + } catch (InvalidKeyException e) { + throw logger.logExceptionAsError(new IllegalArgumentException( + "'sharedAccessKey' is an invalid value for the hashing algorithm.", e)); + } + final String utf8Encoding = UTF_8.name(); final OffsetDateTime expiresOn = OffsetDateTime.now(ZoneOffset.UTC).plus(tokenValidity); final String expiresOnEpochSeconds = Long.toString(expiresOn.toEpochSecond()); From 72ef77a51aa82f5d5dc07247d91426390737c726 Mon Sep 17 00:00:00 2001 From: Gauri Prasad <51212198+gapra-msft@users.noreply.github.com> Date: Mon, 27 Jan 2020 12:28:37 -0800 Subject: [PATCH 2/8] Removed unused constants in BlobAsyncClientBase (#7741) --- .../azure/storage/blob/specialized/BlobAsyncClientBase.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobAsyncClientBase.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobAsyncClientBase.java index 84adcf550b61..ada8f97cd0f6 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobAsyncClientBase.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/BlobAsyncClientBase.java @@ -47,7 +47,6 @@ import com.azure.storage.blob.sas.BlobServiceSasSignatureValues; import com.azure.storage.common.StorageSharedKeyCredential; import com.azure.storage.common.Utility; -import com.azure.storage.common.implementation.Constants; import com.azure.storage.common.implementation.SasImplUtils; import com.azure.storage.common.implementation.StorageImplUtils; import reactor.core.publisher.Flux; @@ -90,9 +89,6 @@ */ public class BlobAsyncClientBase { - private static final int BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE = 4 * Constants.MB; - private static final int BLOB_MAX_DOWNLOAD_BLOCK_SIZE = 100 * Constants.MB; - private final ClientLogger logger = new ClientLogger(BlobAsyncClientBase.class); protected final AzureBlobStorageImpl azureBlobStorage; From 20e3c52884cf977a10ec205bd204ed9590cd4296 Mon Sep 17 00:00:00 2001 From: Srikanta <51379715+srnagar@users.noreply.github.com> Date: Mon, 27 Jan 2020 13:30:07 -0800 Subject: [PATCH 3/8] Increase unit test coverage for checkpoint store and event processor (#7743) * Checkpoint store unit tests * Update unit tests * Fix path for resource file --- .../blob/BlobCheckpointStore.java | 2 +- .../checkpointstore/blob/Messages.java | 41 +++------ .../blob => }/messages.properties | 0 .../BlobEventProcessorClientStoreTest.java | 87 ++++++++++++++++--- .../checkpointstore/blob/MessagesTest.java | 1 - .../eventhubs/EventProcessorClient.java | 35 ++++++-- .../eventhubs/PartitionBasedLoadBalancer.java | 8 +- ...EventProcessorClientErrorHandlingTest.java | 11 +-- .../eventhubs/EventProcessorClientTest.java | 13 ++- 9 files changed, 138 insertions(+), 60 deletions(-) rename sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/resources/{com/azure/messaging/eventhubs/checkpointstore/blob => }/messages.properties (100%) diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobCheckpointStore.java b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobCheckpointStore.java index aed945ae8290..80939c815397 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobCheckpointStore.java +++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobCheckpointStore.java @@ -201,7 +201,7 @@ private Mono updateOwnershipETag(Response response, Parti */ @Override public Mono updateCheckpoint(Checkpoint checkpoint) { - if (checkpoint.getSequenceNumber() == null && checkpoint.getOffset() == null) { + if (checkpoint == null || (checkpoint.getSequenceNumber() == null && checkpoint.getOffset() == null)) { throw logger.logExceptionAsWarning(Exceptions .propagate(new IllegalStateException( "Both sequence number and offset cannot be null when updating a checkpoint"))); diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/Messages.java b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/Messages.java index ddf6ac079301..23cd37ccafc0 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/Messages.java +++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/Messages.java @@ -3,50 +3,29 @@ package com.azure.messaging.eventhubs.checkpointstore.blob; -import com.azure.core.util.logging.ClientLogger; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; +import com.azure.core.util.CoreUtils; +import java.util.Map; /** * I18n messages loaded from the messages.properties file located within the same package. */ public enum Messages { ; - private static final ClientLogger LOGGER = new ClientLogger(Messages.class); - private static Properties properties; - private static final String PATH = "com/azure/messaging/eventhubs/checkpointstore/blob/messages.properties"; - public static final String NO_METADATA_AVAILABLE_FOR_BLOB = "No metadata available for blob {}"; - public static final String CLAIM_ERROR = "Couldn't claim ownership of partition {}"; - public static final String FOUND_BLOB_FOR_PARTITION = "Found blob for partition {}"; - public static final String BLOB_OWNER_INFO = "Blob {} is owned by {}"; - public static final String CHECKPOINT_INFO = "Blob {} has checkpoint with sequence number {} and offset {}"; + private static final String PATH = "messages.properties"; + private static final Map PROPERTIES = CoreUtils.getProperties(PATH); - private static synchronized Properties getProperties() { - if (properties != null) { - return properties; - } - properties = new Properties(); - try (InputStream inputStream = - Thread.currentThread().getContextClassLoader().getResourceAsStream(PATH)) { - if (inputStream != null) { - properties.load(inputStream); - } else { - LOGGER.error("Message properties [{}] not found", PATH); //NON-NLS - } - } catch (IOException exception) { - LOGGER.error("Error loading message properties [{}]", PATH, exception); //NON-NLS - } - return properties; - } + public static final String NO_METADATA_AVAILABLE_FOR_BLOB = getMessage("NO_METADATA_AVAILABLE_FOR_BLOB"); + public static final String CLAIM_ERROR = getMessage("CLAIM_ERROR"); + public static final String FOUND_BLOB_FOR_PARTITION = getMessage("FOUND_BLOB_FOR_PARTITION"); + public static final String BLOB_OWNER_INFO = getMessage("BLOB_OWNER_INFO"); + public static final String CHECKPOINT_INFO = getMessage("CHECKPOINT_INFO"); /** * @param key the key of the message to retrieve * @return the message matching the given key */ public static String getMessage(String key) { - return String.valueOf(getProperties().getOrDefault(key, key)); + return PROPERTIES.getOrDefault(key, key); } } diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/resources/com/azure/messaging/eventhubs/checkpointstore/blob/messages.properties b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/resources/messages.properties similarity index 100% rename from sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/resources/com/azure/messaging/eventhubs/checkpointstore/blob/messages.properties rename to sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/resources/messages.properties diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/test/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobEventProcessorClientStoreTest.java b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/test/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobEventProcessorClientStoreTest.java index be5eac43e485..51f560dc65ad 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/test/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobEventProcessorClientStoreTest.java +++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/test/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobEventProcessorClientStoreTest.java @@ -17,6 +17,7 @@ import com.azure.storage.blob.models.BlobItem; import com.azure.storage.blob.models.BlobItemProperties; import com.azure.storage.blob.models.ListBlobsOptions; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; @@ -35,6 +36,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.when; @@ -61,11 +63,13 @@ public void setup() { @Test public void testListOwnerShip() { BlobCheckpointStore blobCheckpointStore = new BlobCheckpointStore(blobContainerAsyncClient); - BlobItem blobItem = getBlobItem("owner1", "1", "230", "etag", "ns/eh/cg/ownership/0"); - BlobItem blobItem2 = getBlobItem("owner1", "1", "230", "etag", "ns/eh/cg/0"); - PagedFlux response = new PagedFlux(() -> Mono.just(new PagedResponseBase response = new PagedFlux<>(() -> Mono.just(new PagedResponseBase(null, 200, null, - Arrays.asList(blobItem, blobItem2), null, + Arrays.asList(blobItem, blobItem2, blobItem3), null, null))); when(blobContainerAsyncClient.listBlobs(any(ListBlobsOptions.class))).thenReturn(response); @@ -79,6 +83,27 @@ public void testListOwnerShip() { }).verifyComplete(); } + @Test + public void testListCheckpoint() { + BlobCheckpointStore blobCheckpointStore = new BlobCheckpointStore(blobContainerAsyncClient); + BlobItem blobItem = getCheckpointBlobItem("230", "1", "ns/eh/cg/checkpoint/0"); + BlobItem blobItem2 = new BlobItem().setName("ns/eh/cg/checkpoint/1"); + PagedFlux response = new PagedFlux<>(() -> Mono.just(new PagedResponseBase(null, 200, null, + Arrays.asList(blobItem, blobItem2), null, + null))); + when(blobContainerAsyncClient.listBlobs(any(ListBlobsOptions.class))).thenReturn(response); + + StepVerifier.create(blobCheckpointStore.listCheckpoints("ns", "eh", "cg")) + .assertNext(checkpoint -> { + assertEquals("0", checkpoint.getPartitionId()); + assertEquals("eh", checkpoint.getEventHubName()); + assertEquals("cg", checkpoint.getConsumerGroup()); + assertEquals(1L, checkpoint.getSequenceNumber()); + assertEquals(230L, checkpoint.getOffset()); + }).verifyComplete(); + } + @Test public void testUpdateCheckpoint() { Checkpoint checkpoint = new Checkpoint() @@ -89,9 +114,7 @@ public void testUpdateCheckpoint() { .setSequenceNumber(2L) .setOffset(100L); - Map headers = new HashMap<>(); - headers.put("eTag", "etag2"); - BlobItem blobItem = getBlobItem("owner1", "1", "230", "etag", "ns/eh/cg/checkpoint/0"); + BlobItem blobItem = getCheckpointBlobItem("230", "1", "ns/eh/cg/checkpoint/0"); PagedFlux response = new PagedFlux(() -> Mono.just(new PagedResponseBase(null, 200, null, Arrays.asList(blobItem), null, @@ -105,7 +128,44 @@ public void testUpdateCheckpoint() { .thenReturn(Mono.empty()); BlobCheckpointStore blobCheckpointStore = new BlobCheckpointStore(blobContainerAsyncClient); + StepVerifier.create(blobCheckpointStore.updateCheckpoint(checkpoint)).verifyComplete(); + } + + @Test + public void testInvalidCheckpoint() { + BlobCheckpointStore blobCheckpointStore = new BlobCheckpointStore(blobContainerAsyncClient); + Assertions.assertThrows(IllegalStateException.class, () -> blobCheckpointStore.updateCheckpoint(null)); + Assertions + .assertThrows(IllegalStateException.class, () -> blobCheckpointStore.updateCheckpoint(new Checkpoint())); + } + + @Test + public void testUpdateCheckpointForNewPartition() { + Checkpoint checkpoint = new Checkpoint() + .setFullyQualifiedNamespace("ns") + .setEventHubName("eh") + .setConsumerGroup("cg") + .setPartitionId("0") + .setSequenceNumber(2L) + .setOffset(100L); + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.put("eTag", "etag2"); + BlobItem blobItem = getCheckpointBlobItem("230", "1", "ns/eh/cg/checkpoint/0"); + PagedFlux response = new PagedFlux(() -> Mono.just(new PagedResponseBase(null, 200, null, + Arrays.asList(blobItem), null, + null))); + + when(blobContainerAsyncClient.getBlobAsyncClient("ns/eh/cg/checkpoint/0")).thenReturn(blobAsyncClient); + when(blobContainerAsyncClient.listBlobs(any(ListBlobsOptions.class))).thenReturn(response); + when(blobAsyncClient.getBlockBlobAsyncClient()).thenReturn(blockBlobAsyncClient); + when(blobAsyncClient.exists()).thenReturn(Mono.just(false)); + when(blobAsyncClient.getBlockBlobAsyncClient()).thenReturn(blockBlobAsyncClient); + when(blockBlobAsyncClient.uploadWithResponse(ArgumentMatchers.>any(), eq(0L), + isNull(), anyMap(), isNull(), isNull(), isNull())) + .thenReturn(Mono.just(new ResponseBase<>(null, 200, httpHeaders, null, null))); + BlobCheckpointStore blobCheckpointStore = new BlobCheckpointStore(blobContainerAsyncClient); StepVerifier.create(blobCheckpointStore.updateCheckpoint(checkpoint)).verifyComplete(); } @@ -195,9 +255,9 @@ private PartitionOwnership createPartitionOwnership(String fullyQualifiedNamespa .setOwnerId(ownerId); } - private BlobItem getBlobItem(String owner, String sequenceNumber, String offset, String etag, String blobName) { - Map metadata = getMetadata(owner, sequenceNumber, offset); - + private BlobItem getOwnershipBlobItem(String owner, String etag, String blobName) { + Map metadata = new HashMap<>(); + metadata.put("ownerid", owner); BlobItemProperties properties = new BlobItemProperties() .setLastModified(OffsetDateTime.now()) .setETag(etag); @@ -208,11 +268,12 @@ private BlobItem getBlobItem(String owner, String sequenceNumber, String offset, .setProperties(properties); } - private Map getMetadata(String owner, String sequenceNumber, String offset) { + private BlobItem getCheckpointBlobItem(String offset, String sequenceNumber, String blobName) { Map metadata = new HashMap<>(); - metadata.put("ownerid", owner); metadata.put("sequencenumber", sequenceNumber); metadata.put("offset", offset); - return metadata; + return new BlobItem() + .setName(blobName) + .setMetadata(metadata); } } diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/test/java/com/azure/messaging/eventhubs/checkpointstore/blob/MessagesTest.java b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/test/java/com/azure/messaging/eventhubs/checkpointstore/blob/MessagesTest.java index b282389a9d98..68379d1f71f1 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/test/java/com/azure/messaging/eventhubs/checkpointstore/blob/MessagesTest.java +++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/test/java/com/azure/messaging/eventhubs/checkpointstore/blob/MessagesTest.java @@ -3,7 +3,6 @@ package com.azure.messaging.eventhubs.checkpointstore.blob; -import com.azure.messaging.eventhubs.Messages; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; diff --git a/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventProcessorClient.java b/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventProcessorClient.java index 5f138fa8a1a5..00b39108569b 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventProcessorClient.java +++ b/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventProcessorClient.java @@ -9,6 +9,7 @@ import com.azure.messaging.eventhubs.implementation.PartitionProcessor; import com.azure.messaging.eventhubs.models.ErrorContext; import com.azure.messaging.eventhubs.models.EventPosition; +import java.time.Duration; import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -19,6 +20,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.stream.Collectors; import reactor.core.Disposable; import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Schedulers; @@ -49,6 +51,11 @@ public class EventProcessorClient { private final AtomicReference runner = new AtomicReference<>(); private final AtomicReference scheduler = new AtomicReference<>(); + private final String fullyQualifiedNamespace; + private final String eventHubName; + private final String consumerGroup; + + /** * Package-private constructor. Use {@link EventHubClientBuilder} to create an instance. @@ -72,18 +79,22 @@ public class EventProcessorClient { Objects.requireNonNull(consumerGroup, "consumerGroup cannot be null."); Objects.requireNonNull(partitionProcessorFactory, "partitionProcessorFactory cannot be null."); + EventHubAsyncClient eventHubAsyncClient = eventHubClientBuilder.buildAsyncClient(); + this.checkpointStore = Objects.requireNonNull(checkpointStore, "checkpointStore cannot be null"); this.identifier = UUID.randomUUID().toString(); + this.fullyQualifiedNamespace = eventHubAsyncClient.getFullyQualifiedNamespace().toLowerCase(Locale.ROOT); + this.eventHubName = eventHubAsyncClient.getEventHubName().toLowerCase(Locale.ROOT); + this.consumerGroup = consumerGroup.toLowerCase(Locale.ROOT); + logger.info("The instance ID for this event processors is {}", this.identifier); this.partitionPumpManager = new PartitionPumpManager(checkpointStore, partitionProcessorFactory, eventHubClientBuilder, trackLastEnqueuedEventProperties, tracerProvider, initialPartitionEventPosition); - EventHubAsyncClient eventHubAsyncClient = eventHubClientBuilder.buildAsyncClient(); this.partitionBasedLoadBalancer = new PartitionBasedLoadBalancer(this.checkpointStore, eventHubAsyncClient, - eventHubAsyncClient.getFullyQualifiedNamespace().toLowerCase(Locale.ROOT), - eventHubAsyncClient.getEventHubName().toLowerCase(Locale.ROOT), - consumerGroup.toLowerCase(Locale.ROOT), identifier, TimeUnit.MINUTES.toSeconds(1), - partitionPumpManager, processError); + this.fullyQualifiedNamespace, this.eventHubName, this.consumerGroup, this.identifier, + TimeUnit.MINUTES.toSeconds(1), this.partitionPumpManager, processError); + } /** @@ -138,7 +149,7 @@ public synchronized void stop() { } runner.get().dispose(); scheduler.get().dispose(); - this.partitionPumpManager.stopAllPartitionPumps(); + stopProcessing(); } /** @@ -150,4 +161,16 @@ public synchronized void stop() { public synchronized boolean isRunning() { return isRunning.get(); } + + private void stopProcessing() { + partitionPumpManager.stopAllPartitionPumps(); + + // finally, remove ownerid from checkpointstore as the processor is shutting down + checkpointStore.listOwnership(fullyQualifiedNamespace, eventHubName, consumerGroup) + .filter(ownership -> identifier.equals(ownership.getOwnerId())) + .map(ownership -> ownership.setOwnerId("")) + .collect(Collectors.toList()) + .map(checkpointStore::claimOwnership) + .block(Duration.ofSeconds(10)); // block until the checkpoint store is updated + } } diff --git a/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/PartitionBasedLoadBalancer.java b/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/PartitionBasedLoadBalancer.java index de1dd95f565a..17efbc9e5eaa 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/PartitionBasedLoadBalancer.java +++ b/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/PartitionBasedLoadBalancer.java @@ -372,7 +372,8 @@ private void claimOwnership(final Map partitionOwner .warning(Messages.FAILED_TO_CLAIM_OWNERSHIP, ownershipRequest.getPartitionId(), ex.getMessage(), ex)) .collectList() - .zipWith(checkpointStore.listCheckpoints(fullyQualifiedNamespace, eventHubName, consumerGroupName) + .zipWhen(ownershipList -> checkpointStore.listCheckpoints(fullyQualifiedNamespace, eventHubName, + consumerGroupName) .collectMap(checkpoint -> checkpoint.getPartitionId(), Function.identity())) .subscribe(ownedPartitionCheckpointsTuple -> { ownedPartitionCheckpointsTuple.getT1() @@ -381,7 +382,10 @@ private void claimOwnership(final Map partitionOwner ownedPartitionCheckpointsTuple.getT2().get(po.getPartitionId()))); }, ex -> { - throw logger.logExceptionAsError(new RuntimeException("Error while listing checkpoints", ex)); + logger.warning("Error while listing checkpoints", ex); + ErrorContext errorContext = new ErrorContext(partitionAgnosticContext, ex); + processError.accept(errorContext); + throw logger.logExceptionAsError(new IllegalStateException("Error while listing checkpoints", ex)); }); } diff --git a/sdk/eventhubs/azure-messaging-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventProcessorClientErrorHandlingTest.java b/sdk/eventhubs/azure-messaging-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventProcessorClientErrorHandlingTest.java index 2617fbb7ba85..6eab9654497e 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventProcessorClientErrorHandlingTest.java +++ b/sdk/eventhubs/azure-messaging-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventProcessorClientErrorHandlingTest.java @@ -40,9 +40,6 @@ */ public class EventProcessorClientErrorHandlingTest { - private static final String NAMESPACE_NAME = "dummyNamespaceName"; - private static final String DEFAULT_DOMAIN_NAME = "servicebus.windows.net/"; - @Mock private EventHubClientBuilder eventHubClientBuilder; @@ -80,7 +77,11 @@ public void testCheckpointStoreErrors(CheckpointStore checkpointStore) throws In }, new HashMap<>()); client.start(); boolean completed = countDownLatch.await(3, TimeUnit.SECONDS); - client.stop(); + try { + client.stop(); + } catch (IllegalStateException ex) { + // do nothing, expected as the checkpointstores are expected to throw errors + } Assertions.assertTrue(completed); } @@ -185,7 +186,7 @@ public Flux claimOwnership( @Override public Flux listCheckpoints(String fullyQualifiedNamespace, String eventHubName, String consumerGroup) { - return null; + return Flux.empty(); } @Override diff --git a/sdk/eventhubs/azure-messaging-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventProcessorClientTest.java b/sdk/eventhubs/azure-messaging-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventProcessorClientTest.java index 99f1c76abe66..b8ec7873970a 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventProcessorClientTest.java +++ b/sdk/eventhubs/azure-messaging-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventProcessorClientTest.java @@ -143,7 +143,6 @@ public void testWithSimplePartitionProcessor() throws Exception { () -> testPartitionProcessor, checkpointStore, false, tracerProvider, ec -> { }, new HashMap<>()); eventProcessorClient.start(); TimeUnit.SECONDS.sleep(10); - eventProcessorClient.stop(); // Assert assertNotNull(eventProcessorClient.getIdentifier()); @@ -168,6 +167,18 @@ public void testWithSimplePartitionProcessor() throws Exception { verify(consumer1, atLeastOnce()).receiveFromPartition(anyString(), any(EventPosition.class), any(ReceiveOptions.class)); verify(consumer1, atLeastOnce()).close(); + eventProcessorClient.stop(); + StepVerifier.create(checkpointStore.listOwnership("test-ns", "test-eh", "test-consumer")) + .assertNext(partitionOwnership -> { + assertEquals("1", partitionOwnership.getPartitionId(), "Partition"); + assertEquals("test-consumer", partitionOwnership.getConsumerGroup(), "Consumer"); + assertEquals("test-eh", partitionOwnership.getEventHubName(), "EventHub name"); + assertEquals("", partitionOwnership.getOwnerId(), "Owner Id"); + assertTrue(partitionOwnership.getLastModifiedTime() >= beforeTest, "LastModifiedTime"); + assertTrue(partitionOwnership.getLastModifiedTime() <= System.currentTimeMillis(), "LastModifiedTime"); + assertNotNull(partitionOwnership.getETag()); + }).verifyComplete(); + } /** From 8f958aa624cfd38faff36ab4f32f3323bb71b979 Mon Sep 17 00:00:00 2001 From: Gauri Prasad <51212198+gapra-msft@users.noreply.github.com> Date: Tue, 28 Jan 2020 11:22:11 -0800 Subject: [PATCH 4/8] Added Embedme changes for blob and file datalake (#7751) --- sdk/storage/azure-storage-blob/README.md | 71 +++++---- .../com/azure/storage/blob/ReadmeSamples.java | 125 ++++++++++++++++ .../azure-storage-file-datalake/README.md | 88 ++++++----- .../storage/file/datalake/ReadmeSamples.java | 139 ++++++++++++++++++ 4 files changed, 362 insertions(+), 61 deletions(-) create mode 100644 sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/ReadmeSamples.java create mode 100644 sdk/storage/azure-storage-file-datalake/src/samples/java/com/azure/storage/file/datalake/ReadmeSamples.java diff --git a/sdk/storage/azure-storage-blob/README.md b/sdk/storage/azure-storage-blob/README.md index 5a23100d1ff0..2d76eaaf1353 100644 --- a/sdk/storage/azure-storage-blob/README.md +++ b/sdk/storage/azure-storage-blob/README.md @@ -124,51 +124,57 @@ The following sections provide several code snippets covering some of the most c Create a `BlobServiceClient` using the [`sasToken`](#get-credentials) generated above. + ```java BlobServiceClient blobServiceClient = new BlobServiceClientBuilder() - .endpoint("") - .sasToken("") - .buildClient(); + .endpoint("") + .sasToken("") + .buildClient(); ``` or + ```java BlobServiceClient blobServiceClient = new BlobServiceClientBuilder() - .endpoint("" + "?" + "") - .buildClient(); + .endpoint("" + "?" + "") + .buildClient(); ``` ### Create a `BlobContainerClient` Create a `BlobContainerClient` using a `BlobServiceClient`. + ```java BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient("mycontainer"); ``` Create a `BlobContainerClient` from the builder [`sasToken`](#get-credentials) generated above. + ```java BlobContainerClient blobContainerClient = new BlobContainerClientBuilder() - .endpoint("") - .sasToken("") - .containerName("mycontainer") - .buildClient(); + .endpoint("") + .sasToken("") + .containerName("mycontainer") + .buildClient(); ``` or + ```java BlobContainerClient blobContainerClient = new BlobContainerClientBuilder() - .endpoint("" + "/" + "mycontainer" + "?" + "") - .buildClient(); + .endpoint("" + "/" + "mycontainer" + "?" + "") + .buildClient(); ``` ### Create a `BlobClient` Create a `BlobClient` using a `BlobContainerClient`. + ```java BlobClient blobClient = blobContainerClient.getBlobClient("myblob"); ``` @@ -177,27 +183,30 @@ or Create a `BlobClient` from the builder [`sasToken`](#get-credentials) generated above. + ```java BlobClient blobClient = new BlobClientBuilder() - .endpoint("") - .sasToken("") - .containerName("mycontainer") - .blobName("myblob") - .buildClient(); + .endpoint("") + .sasToken("") + .containerName("mycontainer") + .blobName("myblob") + .buildClient(); ``` or + ```java BlobClient blobClient = new BlobClientBuilder() - .endpoint("" + "/" + "mycontainer" + "/" + "myblob" +"?" + "") - .buildClient(); + .endpoint("" + "/" + "mycontainer" + "/" + "myblob" + "?" + "") + .buildClient(); ``` ### Create a container Create a container using a `BlobServiceClient`. + ```java blobServiceClient.createBlobContainer("mycontainer"); ``` @@ -206,6 +215,7 @@ or Create a container using a `BlobContainerClient`. + ```java blobContainerClient.create(); ``` @@ -214,11 +224,14 @@ blobContainerClient.create(); Upload from an `InputStream` to a blob using a `BlockBlobClient` generated from a `BlobContainerClient`. + ```java BlockBlobClient blockBlobClient = blobContainerClient.getBlobClient("myblockblob").getBlockBlobClient(); String dataSample = "samples"; try (ByteArrayInputStream dataStream = new ByteArrayInputStream(dataSample.getBytes())) { blockBlobClient.upload(dataStream, dataSample.length()); +} catch (IOException e) { + e.printStackTrace(); } ``` @@ -226,6 +239,7 @@ try (ByteArrayInputStream dataStream = new ByteArrayInputStream(dataSample.getBy Upload a file to a blob using a `BlobClient` generated from a `BlobContainerClient`. + ```java BlobClient blobClient = blobContainerClient.getBlobClient("myblockblob"); blobClient.uploadFromFile("local-file.jpg"); @@ -235,9 +249,12 @@ blobClient.uploadFromFile("local-file.jpg"); Download a blob to an `OutputStream` using a `BlobClient`. + ```java -try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { +try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { blobClient.download(outputStream); +} catch (IOException e) { + e.printStackTrace(); } ``` @@ -245,6 +262,7 @@ try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { Download blob to a local file using a `BlobClient`. + ```java blobClient.downloadToFile("downloaded-file.jpg"); ``` @@ -253,22 +271,23 @@ blobClient.downloadToFile("downloaded-file.jpg"); Enumerating all blobs using a `BlobContainerClient`. + ```java -Iterator it = blobContainerClient.listBlobs().iterator(); -it.forEachRemaining( - { blobItem -> System.out.println("This is the blob name: " + blobItem.getName()) } - ); +for (BlobItem blobItem : blobContainerClient.listBlobs()) { + System.out.println("This is the blob name: " + blobItem.getName()); +} ``` ### Authenticate with Azure Identity The [Azure Identity library][identity] provides Azure Active Directory support for authenticating with Azure Storage. + ```java BlobServiceClient blobStorageClient = new BlobServiceClientBuilder() - .endpoint(endpoint) - .credential(new DefaultAzureCredentialBuilder().build()) - .buildClient(); + .endpoint("") + .credential(new DefaultAzureCredentialBuilder().build()) + .buildClient(); ``` ## Troubleshooting diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/ReadmeSamples.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/ReadmeSamples.java new file mode 100644 index 000000000000..003e72f8e6a3 --- /dev/null +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/ReadmeSamples.java @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.blob; + +import com.azure.identity.DefaultAzureCredentialBuilder; +import com.azure.storage.blob.models.BlobItem; +import com.azure.storage.blob.specialized.BlockBlobClient; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * WARNING: MODIFYING THIS FILE WILL REQUIRE CORRESPONDING UPDATES TO README.md FILE. LINE NUMBERS + * ARE USED TO EXTRACT APPROPRIATE CODE SEGMENTS FROM THIS FILE. ADD NEW CODE AT THE BOTTOM TO AVOID CHANGING + * LINE NUMBERS OF EXISTING CODE SAMPLES. + * + * Code samples for the README.md + */ +public class ReadmeSamples { + + private BlobServiceClient blobServiceClient = new BlobServiceClientBuilder().buildClient(); + private BlobContainerClient blobContainerClient = new BlobContainerClientBuilder().buildClient(); + private BlobClient blobClient = new BlobClientBuilder().buildClient(); + + public void getBlobServiceClient1() { + BlobServiceClient blobServiceClient = new BlobServiceClientBuilder() + .endpoint("") + .sasToken("") + .buildClient(); + } + + public void getBlobServiceClient2() { + BlobServiceClient blobServiceClient = new BlobServiceClientBuilder() + .endpoint("" + "?" + "") + .buildClient(); + } + + public void getBlobContainerClient1() { + BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient("mycontainer"); + } + + public void getBlobContainerClient2() { + BlobContainerClient blobContainerClient = new BlobContainerClientBuilder() + .endpoint("") + .sasToken("") + .containerName("mycontainer") + .buildClient(); + } + + public void getBlobContainerClient3() { + BlobContainerClient blobContainerClient = new BlobContainerClientBuilder() + .endpoint("" + "/" + "mycontainer" + "?" + "") + .buildClient(); + } + + public void getBlobClient1() { + BlobClient blobClient = blobContainerClient.getBlobClient("myblob"); + } + + public void getBlobClient2() { + BlobClient blobClient = new BlobClientBuilder() + .endpoint("") + .sasToken("") + .containerName("mycontainer") + .blobName("myblob") + .buildClient(); + } + + public void getBlobClient3() { + BlobClient blobClient = new BlobClientBuilder() + .endpoint("" + "/" + "mycontainer" + "/" + "myblob" + "?" + "") + .buildClient(); + } + + public void createBlobContainerClient1() { + blobServiceClient.createBlobContainer("mycontainer"); + } + + public void createBlobContainerClient2() { + blobContainerClient.create(); + } + + public void uploadBlobFromStream() { + BlockBlobClient blockBlobClient = blobContainerClient.getBlobClient("myblockblob").getBlockBlobClient(); + String dataSample = "samples"; + try (ByteArrayInputStream dataStream = new ByteArrayInputStream(dataSample.getBytes())) { + blockBlobClient.upload(dataStream, dataSample.length()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void uploadBlobFromFile() { + BlobClient blobClient = blobContainerClient.getBlobClient("myblockblob"); + blobClient.uploadFromFile("local-file.jpg"); + } + + public void downloadBlobToStream() { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + blobClient.download(outputStream); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void downloadBlobToFile() { + blobClient.downloadToFile("downloaded-file.jpg"); + } + + public void enumerateBlobs() { + for (BlobItem blobItem : blobContainerClient.listBlobs()) { + System.out.println("This is the blob name: " + blobItem.getName()); + } + } + + public void authWithIdentity() { + BlobServiceClient blobStorageClient = new BlobServiceClientBuilder() + .endpoint("") + .credential(new DefaultAzureCredentialBuilder().build()) + .buildClient(); + } + +} + diff --git a/sdk/storage/azure-storage-file-datalake/README.md b/sdk/storage/azure-storage-file-datalake/README.md index 71da4b117273..fb91fbf7da17 100644 --- a/sdk/storage/azure-storage-file-datalake/README.md +++ b/sdk/storage/azure-storage-file-datalake/README.md @@ -148,25 +148,28 @@ The following sections provide several code snippets covering some of the most c Create a `DataLakeServiceClient` using the [`sasToken`](#get-credentials) generated above. + ```java DataLakeServiceClient dataLakeServiceClient = new DataLakeServiceClientBuilder() - .endpoint("") - .sasToken("") - .buildClient(); + .endpoint("") + .sasToken("") + .buildClient(); ``` or + ```java DataLakeServiceClient dataLakeServiceClient = new DataLakeServiceClientBuilder() - .endpoint("" + "?" + "") - .buildClient(); + .endpoint("" + "?" + "") + .buildClient(); ``` ### Create a `DataLakeFileSystemClient` Create a `DataLakeFileSystemClient` using a `DataLakeServiceClient`. + ```java DataLakeFileSystemClient dataLakeFileSystemClient = dataLakeServiceClient.getFileSystemClient("myfilesystem"); ``` @@ -175,26 +178,29 @@ or Create a `DataLakeFileSystemClient` from the builder [`sasToken`](#get-credentials) generated above. + ```java DataLakeFileSystemClient dataLakeFileSystemClient = new DataLakeFileSystemClientBuilder() - .endpoint("") - .sasToken("") - .fileSystemName("myfilesystem") - .buildClient(); + .endpoint("") + .sasToken("") + .fileSystemName("myfilesystem") + .buildClient(); ``` or + ```java DataLakeFileSystemClient dataLakeFileSystemClient = new DataLakeFileSystemClientBuilder() - .endpoint("" + "/" + "myfilesystem" + "?" + "") - .buildClient(); + .endpoint("" + "/" + "myfilesystem" + "?" + "") + .buildClient(); ``` ### Create a `DataLakeFileClient` Create a `DataLakeFileClient` using a `DataLakeFileSystemClient`. + ```java DataLakeFileClient fileClient = dataLakeFileSystemClient.getFileClient("myfile"); ``` @@ -203,27 +209,30 @@ or Create a `FileClient` from the builder [`sasToken`](#get-credentials) generated above. + ```java DataLakeFileClient fileClient = new DataLakePathClientBuilder() - .endpoint("") - .sasToken("") - .fileSystemName("myfilesystem") - .pathName("myfile") - .buildClient(); + .endpoint("") + .sasToken("") + .fileSystemName("myfilesystem") + .pathName("myfile") + .buildFileClient(); ``` or + ```java DataLakeFileClient fileClient = new DataLakePathClientBuilder() - .endpoint("" + "/" + "myfilesystem" + "/" + "myfile" +"?" + "") - .buildClient(); + .endpoint("" + "/" + "myfilesystem" + "/" + "myfile" + "?" + "") + .buildFileClient(); ``` ### Create a `DataLakeDirectoryClient` Get a `DataLakeDirectoryClient` using a `DataLakeFileSystemClient`. + ```java DataLakeDirectoryClient directoryClient = dataLakeFileSystemClient.getDirectoryClient("mydir"); ``` @@ -232,27 +241,30 @@ or Create a `DirectoryClient` from the builder [`sasToken`](#get-credentials) generated above. + ```java DataLakeDirectoryClient directoryClient = new DataLakePathClientBuilder() - .endpoint("") - .sasToken("") - .fileSystemName("myfilesystem") - .pathName("mydir") - .buildClient(); + .endpoint("") + .sasToken("") + .fileSystemName("myfilesystem") + .pathName("mydir") + .buildDirectoryClient(); ``` or + ```java -DataLakeFileClient fileClient = new DataLakePathClientBuilder() - .endpoint("" + "/" + "myfilesystem" + "/" + "mydir" +"?" + "") - .buildClient(); +DataLakeDirectoryClient directoryClient = new DataLakePathClientBuilder() + .endpoint("" + "/" + "myfilesystem" + "/" + "mydir" + "?" + "") + .buildDirectoryClient(); ``` ### Create a file system Create a file system using a `DataLakeServiceClient`. + ```java dataLakeServiceClient.createFileSystem("myfilesystem"); ``` @@ -261,6 +273,7 @@ or Create a file system using a `DataLakeFileSystemClient`. + ```java dataLakeFileSystemClient.create(); ``` @@ -269,37 +282,40 @@ dataLakeFileSystemClient.create(); Enumerating all paths using a `DataLakeFileSystemClient`. + ```java -Iterator it = dataLakeFileSystemClient.listPaths().iterator(); -it.forEachRemaining( - { pathItem -> System.out.println("This is the path name: " + pathItem.getName()) } - ); +for (PathItem pathItem : dataLakeFileSystemClient.listPaths()) { + System.out.println("This is the path name: " + pathItem.getName()); +} ``` ### Rename a file Rename a file using a `DataLakeFileClient`. + ```java DataLakeFileClient fileClient = dataLakeFileSystemClient.getFileClient("myfile"); fileClient.create(); -fileClient.rename("new-file-name") +fileClient.rename("new-file-system-name", "new-file-name"); ``` ### Rename a directory Rename a directory using a `DataLakeDirectoryClient`. + ```java DataLakeDirectoryClient directoryClient = dataLakeFileSystemClient.getDirectoryClient("mydir"); directoryClient.create(); -directoryClient.rename("new-directory-name") +directoryClient.rename("new-file-system-name", "new-directory-name"); ``` ### Get file properties Get properties from a file using a `DataLakeFileClient`. + ```java DataLakeFileClient fileClient = dataLakeFileSystemClient.getFileClient("myfile"); fileClient.create(); @@ -310,6 +326,7 @@ PathProperties properties = fileClient.getProperties(); Get properties from a directory using a `DataLakeDirectoryClient`. + ```java DataLakeDirectoryClient directoryClient = dataLakeFileSystemClient.getDirectoryClient("mydir"); directoryClient.create(); @@ -320,11 +337,12 @@ PathProperties properties = directoryClient.getProperties(); The [Azure Identity library][identity] provides Azure Active Directory support for authenticating with Azure Storage. + ```java DataLakeServiceClient storageClient = new DataLakeServiceClientBuilder() - .endpoint(endpoint) - .credential(new DefaultAzureCredentialBuilder().build()) - .buildClient(); + .endpoint("") + .credential(new DefaultAzureCredentialBuilder().build()) + .buildClient(); ``` ## Troubleshooting diff --git a/sdk/storage/azure-storage-file-datalake/src/samples/java/com/azure/storage/file/datalake/ReadmeSamples.java b/sdk/storage/azure-storage-file-datalake/src/samples/java/com/azure/storage/file/datalake/ReadmeSamples.java new file mode 100644 index 000000000000..6990f330d2d7 --- /dev/null +++ b/sdk/storage/azure-storage-file-datalake/src/samples/java/com/azure/storage/file/datalake/ReadmeSamples.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.datalake; + +import com.azure.identity.DefaultAzureCredentialBuilder; +import com.azure.storage.file.datalake.models.PathItem; +import com.azure.storage.file.datalake.models.PathProperties; + +/** + * WARNING: MODIFYING THIS FILE WILL REQUIRE CORRESPONDING UPDATES TO README.md FILE. LINE NUMBERS + * ARE USED TO EXTRACT APPROPRIATE CODE SEGMENTS FROM THIS FILE. ADD NEW CODE AT THE BOTTOM TO AVOID CHANGING + * LINE NUMBERS OF EXISTING CODE SAMPLES. + * + * Code samples for the README.md + */ +public class ReadmeSamples { + + private DataLakeServiceClient dataLakeServiceClient = new DataLakeServiceClientBuilder().buildClient(); + private DataLakeFileSystemClient dataLakeFileSystemClient = new DataLakeFileSystemClientBuilder().buildClient(); + private DataLakeFileClient dataLakeFileClient = new DataLakePathClientBuilder().buildFileClient(); + private DataLakeDirectoryClient dataLakeDirectoryClient = new DataLakePathClientBuilder().buildDirectoryClient(); + + public void getDataLakeServiceClient1() { + DataLakeServiceClient dataLakeServiceClient = new DataLakeServiceClientBuilder() + .endpoint("") + .sasToken("") + .buildClient(); + } + + public void getDataLakeServiceClient2() { + DataLakeServiceClient dataLakeServiceClient = new DataLakeServiceClientBuilder() + .endpoint("" + "?" + "") + .buildClient(); + } + + public void getDataLakeFileSystemClient1() { + DataLakeFileSystemClient dataLakeFileSystemClient = dataLakeServiceClient.getFileSystemClient("myfilesystem"); + } + + public void getDataLakeFileSystemClient2() { + DataLakeFileSystemClient dataLakeFileSystemClient = new DataLakeFileSystemClientBuilder() + .endpoint("") + .sasToken("") + .fileSystemName("myfilesystem") + .buildClient(); + } + + public void getDataLakeFileSystemClient3() { + DataLakeFileSystemClient dataLakeFileSystemClient = new DataLakeFileSystemClientBuilder() + .endpoint("" + "/" + "myfilesystem" + "?" + "") + .buildClient(); + } + + public void getFileClient1() { + DataLakeFileClient fileClient = dataLakeFileSystemClient.getFileClient("myfile"); + } + + public void getFileClient2() { + DataLakeFileClient fileClient = new DataLakePathClientBuilder() + .endpoint("") + .sasToken("") + .fileSystemName("myfilesystem") + .pathName("myfile") + .buildFileClient(); + } + + public void getFileClient3() { + DataLakeFileClient fileClient = new DataLakePathClientBuilder() + .endpoint("" + "/" + "myfilesystem" + "/" + "myfile" + "?" + "") + .buildFileClient(); + } + + public void getDirClient1() { + DataLakeDirectoryClient directoryClient = dataLakeFileSystemClient.getDirectoryClient("mydir"); + } + + public void getDirClient2() { + DataLakeDirectoryClient directoryClient = new DataLakePathClientBuilder() + .endpoint("") + .sasToken("") + .fileSystemName("myfilesystem") + .pathName("mydir") + .buildDirectoryClient(); + } + + public void getDirClient3() { + DataLakeDirectoryClient directoryClient = new DataLakePathClientBuilder() + .endpoint("" + "/" + "myfilesystem" + "/" + "mydir" + "?" + "") + .buildDirectoryClient(); + } + + public void createDataLakeFileSystemClient1() { + dataLakeServiceClient.createFileSystem("myfilesystem"); + } + + public void createDataLakeFileSystemClient2() { + dataLakeFileSystemClient.create(); + } + + public void enumeratePaths() { + for (PathItem pathItem : dataLakeFileSystemClient.listPaths()) { + System.out.println("This is the path name: " + pathItem.getName()); + } + } + + public void renameFile() { + DataLakeFileClient fileClient = dataLakeFileSystemClient.getFileClient("myfile"); + fileClient.create(); + fileClient.rename("new-file-system-name", "new-file-name"); + } + + public void renameDirectory() { + DataLakeDirectoryClient directoryClient = dataLakeFileSystemClient.getDirectoryClient("mydir"); + directoryClient.create(); + directoryClient.rename("new-file-system-name", "new-directory-name"); + } + + public void getPropertiesFile() { + DataLakeFileClient fileClient = dataLakeFileSystemClient.getFileClient("myfile"); + fileClient.create(); + PathProperties properties = fileClient.getProperties(); + } + + public void getPropertiesDirectory() { + DataLakeDirectoryClient directoryClient = dataLakeFileSystemClient.getDirectoryClient("mydir"); + directoryClient.create(); + PathProperties properties = directoryClient.getProperties(); + } + + public void authWithIdentity() { + DataLakeServiceClient storageClient = new DataLakeServiceClientBuilder() + .endpoint("") + .credential(new DefaultAzureCredentialBuilder().build()) + .buildClient(); + } + +} + From 8eeb2a3a6ad52eb31b8a4e4f574b00b2e8a811c2 Mon Sep 17 00:00:00 2001 From: Gauri Prasad <51212198+gapra-msft@users.noreply.github.com> Date: Tue, 28 Jan 2020 12:00:16 -0800 Subject: [PATCH 5/8] Fixed bug where root directory client could not be used to create files (#7748) --- .../azure-storage-file-share/CHANGELOG.md | 3 ++ .../file/share/ShareDirectoryAsyncClient.java | 4 ++ .../storage/file/share/ShareAPITests.groovy | 13 +++++ ...hareAPITestsCreateFileInRootDirectory.json | 54 +++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 sdk/storage/azure-storage-file-share/src/test/resources/session-records/ShareAPITestsCreateFileInRootDirectory.json diff --git a/sdk/storage/azure-storage-file-share/CHANGELOG.md b/sdk/storage/azure-storage-file-share/CHANGELOG.md index 89e68b3aab4a..82e6d6497c63 100644 --- a/sdk/storage/azure-storage-file-share/CHANGELOG.md +++ b/sdk/storage/azure-storage-file-share/CHANGELOG.md @@ -1,5 +1,8 @@ # Release History +## 12.2.0-beta.1 (Unreleased) +- Fixed bug where ShareDirectoryAsyncClient.getFileClient appended an extra / for files in the root directory. + ## 12.1.0 (2020-01-08) This package's [documentation](https://github.com/Azure/azure-sdk-for-java/blob/azure-storage-file_12.1.0/sdk/storage/azure-storage-file-share/README.md) diff --git a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareDirectoryAsyncClient.java b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareDirectoryAsyncClient.java index 71fcc1568e91..de7c24400910 100644 --- a/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareDirectoryAsyncClient.java +++ b/sdk/storage/azure-storage-file-share/src/main/java/com/azure/storage/file/share/ShareDirectoryAsyncClient.java @@ -134,6 +134,10 @@ public ShareServiceVersion getServiceVersion() { */ public ShareFileAsyncClient getFileClient(String fileName) { String filePath = directoryPath + "/" + fileName; + // Support for root directory + if (directoryPath.isEmpty()) { + filePath = fileName; + } return new ShareFileAsyncClient(azureFileStorageClient, shareName, filePath, null, accountName, serviceVersion); } diff --git a/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/ShareAPITests.groovy b/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/ShareAPITests.groovy index 3d9921fa6375..aa9c88d874cf 100644 --- a/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/ShareAPITests.groovy +++ b/sdk/storage/azure-storage-file-share/src/test/java/com/azure/storage/file/share/ShareAPITests.groovy @@ -4,7 +4,10 @@ package com.azure.storage.file.share import com.azure.core.http.netty.NettyAsyncHttpClientBuilder +import com.azure.core.http.rest.Response +import com.azure.core.util.Context import com.azure.storage.common.StorageSharedKeyCredential +import com.azure.storage.common.implementation.Constants import com.azure.storage.file.share.models.NtfsFileAttributes import com.azure.storage.file.share.models.ShareErrorCode import com.azure.storage.file.share.models.ShareFileHttpHeaders @@ -386,6 +389,16 @@ class ShareAPITests extends APISpec { "fileName" | 1024 | null | Collections.singletonMap("", "value") | ShareErrorCode.EMPTY_METADATA_KEY } + def "Create file in root directory"() { + given: + primaryShareClient.create() + def directoryClient = primaryShareClient.getRootDirectoryClient() + + expect: + FileTestHelper.assertResponseStatusCode( + directoryClient.createFileWithResponse("testCreateFile", 1024, null, null, null, null, null, null), 201) + } + def "Delete directory"() { given: def directoryName = "testCreateDirectory" diff --git a/sdk/storage/azure-storage-file-share/src/test/resources/session-records/ShareAPITestsCreateFileInRootDirectory.json b/sdk/storage/azure-storage-file-share/src/test/resources/session-records/ShareAPITestsCreateFileInRootDirectory.json new file mode 100644 index 000000000000..cfa41de174e5 --- /dev/null +++ b/sdk/storage/azure-storage-file-share/src/test/resources/session-records/ShareAPITestsCreateFileInRootDirectory.json @@ -0,0 +1,54 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "http://gaprastg71.file.core.windows.net/shareapitestscreatefileinrootdirectory0432183cec74f?restype=share", + "Headers" : { + "x-ms-version" : "2019-02-02", + "User-Agent" : "azsdk-java-azure-storage-file-share/12.2.0-beta.1 (11.0.4; Windows 10 10.0)", + "x-ms-client-request-id" : "d83ba1d1-f731-4c5d-9b31-b307fa8bf6d4" + }, + "Response" : { + "x-ms-version" : "2019-02-02", + "Server" : "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "ETag" : "0x8D7A36E16B4FD84", + "Last-Modified" : "Mon, 27 Jan 2020 21:15:51 GMT", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "4d3fde2d-201a-0001-7856-d5cde7000000", + "Date" : "Mon, 27 Jan 2020 21:15:51 GMT", + "x-ms-client-request-id" : "d83ba1d1-f731-4c5d-9b31-b307fa8bf6d4" + }, + "Exception" : null + }, { + "Method" : "PUT", + "Uri" : "http://gaprastg71.file.core.windows.net/shareapitestscreatefileinrootdirectory0432183cec74f/testCreateFile", + "Headers" : { + "x-ms-version" : "2019-02-02", + "User-Agent" : "azsdk-java-azure-storage-file-share/12.2.0-beta.1 (11.0.4; Windows 10 10.0)", + "x-ms-client-request-id" : "0530f34d-7eee-4941-a8f3-7465c4b0ca39" + }, + "Response" : { + "x-ms-version" : "2019-02-02", + "x-ms-file-permission-key" : "15729343842853002337*8280205063999649007", + "x-ms-file-id" : "13835128424026341376", + "Server" : "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-file-creation-time" : "2020-01-27T21:15:52.0821414Z", + "Last-Modified" : "Mon, 27 Jan 2020 21:15:52 GMT", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-server-encrypted" : "true", + "Date" : "Mon, 27 Jan 2020 21:15:51 GMT", + "ETag" : "0x8D7A36E16D23CA6", + "x-ms-file-attributes" : "Archive", + "x-ms-file-change-time" : "2020-01-27T21:15:52.0821414Z", + "x-ms-file-parent-id" : "0", + "Content-Length" : "0", + "x-ms-request-id" : "4d3fde3c-201a-0001-0156-d5cde7000000", + "x-ms-client-request-id" : "0530f34d-7eee-4941-a8f3-7465c4b0ca39", + "x-ms-file-last-write-time" : "2020-01-27T21:15:52.0821414Z" + }, + "Exception" : null + } ], + "variables" : [ "shareapitestscreatefileinrootdirectory0432183cec74f" ] +} \ No newline at end of file From ff6bc1b6b8b1d4ab45aa2f1942f09f59fece0152 Mon Sep 17 00:00:00 2001 From: Srikanta <51379715+srnagar@users.noreply.github.com> Date: Tue, 28 Jan 2020 13:49:35 -0800 Subject: [PATCH 6/8] Handle null ownerIds in checkpoint store (#7750) * Handle null ownerIds in checkpoint store * Disambiguate message properties file --- .../blob/BlobCheckpointStore.java | 8 ++++- .../checkpointstore/blob/Messages.java | 2 +- ...-checkpointstore-blob-messages.properties} | 0 .../eventhubs/EventProcessorClient.java | 4 +-- .../azure/messaging/eventhubs/Messages.java | 35 ++++--------------- ...operties => eventhubs-messages.properties} | 2 -- 6 files changed, 16 insertions(+), 35 deletions(-) rename sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/resources/{messages.properties => eventhubs-checkpointstore-blob-messages.properties} (100%) rename sdk/eventhubs/azure-messaging-eventhubs/src/main/resources/{com/azure/messaging/eventhubs/messages.properties => eventhubs-messages.properties} (89%) diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobCheckpointStore.java b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobCheckpointStore.java index 80939c815397..97c94adff20e 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobCheckpointStore.java +++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/BlobCheckpointStore.java @@ -260,13 +260,19 @@ private Mono convertToPartitionOwnership(BlobItem blobItem) .info(Messages.BLOB_OWNER_INFO, blobItem.getName(), blobItem.getMetadata().getOrDefault(OWNER_ID, "")); BlobItemProperties blobProperties = blobItem.getProperties(); + + String ownerId = blobItem.getMetadata().getOrDefault(OWNER_ID, ""); + if (ownerId == null) { + return Mono.empty(); + } + PartitionOwnership partitionOwnership = new PartitionOwnership() .setFullyQualifiedNamespace(names[0]) .setEventHubName(names[1]) .setConsumerGroup(names[2]) // names[3] is "ownership" .setPartitionId(names[4]) - .setOwnerId(blobItem.getMetadata().getOrDefault(OWNER_ID, "")) + .setOwnerId(ownerId) .setLastModifiedTime(blobProperties.getLastModified().toInstant().toEpochMilli()) .setETag(blobProperties.getETag()); return Mono.just(partitionOwnership); diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/Messages.java b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/Messages.java index 23cd37ccafc0..b3fc0b534961 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/Messages.java +++ b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/java/com/azure/messaging/eventhubs/checkpointstore/blob/Messages.java @@ -11,7 +11,7 @@ */ public enum Messages { ; - private static final String PATH = "messages.properties"; + private static final String PATH = "eventhubs-checkpointstore-blob-messages.properties"; private static final Map PROPERTIES = CoreUtils.getProperties(PATH); public static final String NO_METADATA_AVAILABLE_FOR_BLOB = getMessage("NO_METADATA_AVAILABLE_FOR_BLOB"); diff --git a/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/resources/messages.properties b/sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/resources/eventhubs-checkpointstore-blob-messages.properties similarity index 100% rename from sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/resources/messages.properties rename to sdk/eventhubs/azure-messaging-eventhubs-checkpointstore-blob/src/main/resources/eventhubs-checkpointstore-blob-messages.properties diff --git a/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventProcessorClient.java b/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventProcessorClient.java index 00b39108569b..b72acfa4054c 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventProcessorClient.java +++ b/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventProcessorClient.java @@ -170,7 +170,7 @@ private void stopProcessing() { .filter(ownership -> identifier.equals(ownership.getOwnerId())) .map(ownership -> ownership.setOwnerId("")) .collect(Collectors.toList()) - .map(checkpointStore::claimOwnership) - .block(Duration.ofSeconds(10)); // block until the checkpoint store is updated + .flatMapMany(checkpointStore::claimOwnership) + .blockLast(Duration.ofSeconds(10)); // block until the checkpoint store is updated } } diff --git a/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/Messages.java b/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/Messages.java index 0580ea3468bc..7a18084a7770 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/Messages.java +++ b/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/Messages.java @@ -3,20 +3,17 @@ package com.azure.messaging.eventhubs; -import com.azure.core.util.logging.ClientLogger; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; +import com.azure.core.util.CoreUtils; +import java.util.Map; /** * I18n messages loaded from the messages.properties file located within the same package. */ public enum Messages { ; - private static final ClientLogger LOGGER = new ClientLogger(Messages.class); - private static Properties properties; - private static final String MESSAGES_PROPERTIES_PATH = "com/azure/messaging/eventhubs/messages.properties"; + private static final String MESSAGES_PROPERTIES_PATH = "eventhubs-messages.properties"; + private static final Map PROPERTIES = CoreUtils.getProperties(MESSAGES_PROPERTIES_PATH); + public static final String CLASS_NOT_A_SUPPORTED_TYPE = getMessage("CLASS_NOT_A_SUPPORTED_TYPE"); public static final String ENCODING_TYPE_NOT_SUPPORTED = getMessage("ENCODING_TYPE_NOT_SUPPORTED"); public static final String PROCESS_SPAN_SCOPE_TYPE_ERROR = getMessage("PROCESS_SPAN_SCOPE_TYPE_ERROR"); @@ -28,35 +25,15 @@ public enum Messages { public static final String FAILED_TO_CLAIM_OWNERSHIP = getMessage("FAILED_TO_CLAIM_OWNERSHIP"); public static final String LOAD_BALANCING_FAILED = getMessage("LOAD_BALANCING_FAILED"); public static final String EVENT_PROCESSOR_RUN_END = getMessage("EVENT_PROCESSOR_RUN_END"); - public static final String FAILED_PROCESSING_ERROR_RECEIVE = getMessage("FAILED_PROCESSING_ERROR_RECEIVE"); - public static final String FAILED_WHILE_PROCESSING_ERROR = getMessage("FAILED_WHILE_PROCESSING_ERROR"); public static final String FAILED_CLOSE_CONSUMER_PARTITION = getMessage("FAILED_CLOSE_CONSUMER_PARTITION"); public static final String ERROR_OCCURRED_IN_SUBSCRIBER_ERROR = getMessage("ERROR_OCCURRED_IN_SUBSCRIBER_ERROR"); public static final String EXCEPTION_OCCURRED_WHILE_EMITTING = getMessage("EXCEPTION_OCCURRED_WHILE_EMITTING"); - private static synchronized Properties getProperties() { - if (properties != null) { - return properties; - } - properties = new Properties(); - try (InputStream inputStream = - Thread.currentThread().getContextClassLoader().getResourceAsStream(MESSAGES_PROPERTIES_PATH)) { - if (inputStream != null) { - properties.load(inputStream); - } else { - LOGGER.error("Message properties [{}] not found", MESSAGES_PROPERTIES_PATH); //NON-NLS - } - } catch (IOException exception) { - LOGGER.error("Error loading message properties [{}]", MESSAGES_PROPERTIES_PATH, exception); //NON-NLS - } - return properties; - } - /** * @param key the key of the message to retrieve * @return the message matching the given key */ public static String getMessage(String key) { - return String.valueOf(getProperties().getOrDefault(key, key)); + return PROPERTIES.getOrDefault(key, key); } } diff --git a/sdk/eventhubs/azure-messaging-eventhubs/src/main/resources/com/azure/messaging/eventhubs/messages.properties b/sdk/eventhubs/azure-messaging-eventhubs/src/main/resources/eventhubs-messages.properties similarity index 89% rename from sdk/eventhubs/azure-messaging-eventhubs/src/main/resources/com/azure/messaging/eventhubs/messages.properties rename to sdk/eventhubs/azure-messaging-eventhubs/src/main/resources/eventhubs-messages.properties index c3f1ffcbf7cb..38e79639dbde 100644 --- a/sdk/eventhubs/azure-messaging-eventhubs/src/main/resources/com/azure/messaging/eventhubs/messages.properties +++ b/sdk/eventhubs/azure-messaging-eventhubs/src/main/resources/eventhubs-messages.properties @@ -7,8 +7,6 @@ ERROR_SENDING_BATCH=Error sending batch. FAILED_TO_CLAIM_OWNERSHIP=Failed to claim ownership of partition {} - {} LOAD_BALANCING_FAILED=Load balancing for event processor failed - {} EVENT_PROCESSOR_RUN_END=EventProcessor.run() endTracingSpan().close() failed with an error %s -FAILED_PROCESSING_ERROR_RECEIVE=Failed while processing error on receive {} -FAILED_WHILE_PROCESSING_ERROR=Failed while processing error {} FAILED_CLOSE_CONSUMER_PARTITION=Failed to close consumer for partition {} ERROR_OCCURRED_IN_SUBSCRIBER_ERROR=Error occurred in subscriber. Error: {} EXCEPTION_OCCURRED_WHILE_EMITTING=Exception occurred while emitting next received event. From 980616d05e14a1e150a51c2951531e0be7772dc3 Mon Sep 17 00:00:00 2001 From: Shawn Fang <45607042+mssfang@users.noreply.github.com> Date: Tue, 28 Jan 2020 14:10:52 -0800 Subject: [PATCH 7/8] [Feature] To be able to rotate subscription key (#7596) * Add the ability to rotate the subscription key. * In addition, increase test coverage to TextAnalyticsClientBuilder. --- .../checkstyle/checkstyle-suppressions.xml | 3 +- .../azure-ai-textanalytics/README.md | 60 ++++--- .../TextAnalyticsClientBuilder.java | 35 ++-- .../SubscriptionKeyCredentialPolicy.java | 36 +++++ .../models/TextAnalyticsApiKeyCredential.java | 45 ++++++ .../src/samples/README.md | 52 ++++-- .../ai/textanalytics/AnalyzeSentiment.java | 5 +- .../textanalytics/AnalyzeSentimentAsync.java | 5 +- .../ai/textanalytics/DetectLanguage.java | 5 +- .../ai/textanalytics/DetectLanguageAsync.java | 5 +- .../ai/textanalytics/ExtractKeyPhrases.java | 6 +- .../textanalytics/ExtractKeyPhrasesAsync.java | 6 +- .../azure/ai/textanalytics/ReadmeSamples.java | 26 ++- .../ai/textanalytics/RecognizeEntities.java | 5 +- .../textanalytics/RecognizeEntitiesAsync.java | 5 +- .../RecognizeLinkedEntities.java | 5 +- .../RecognizeLinkedEntitiesAsync.java | 5 +- .../azure/ai/textanalytics/RecognizePii.java | 5 +- .../ai/textanalytics/RecognizePiiAsync.java | 5 +- .../textanalytics/RotateSubscriptionKey.java | 42 +++++ .../RotateSubscriptionKeyAsync.java | 59 +++++++ ...alyticsAsyncClientJavaDocCodeSnippets.java | 24 ++- ...extAnalyticsClientJavaDocCodeSnippets.java | 11 +- .../batch/AnalyzeSentimentBatchDocuments.java | 5 +- .../AnalyzeSentimentBatchDocumentsAsync.java | 5 +- .../batch/DetectLanguageBatchDocuments.java | 5 +- .../DetectLanguageBatchDocumentsAsync.java | 5 +- .../ExtractKeyPhrasesBatchDocuments.java | 5 +- .../ExtractKeyPhrasesBatchDocumentsAsync.java | 5 +- .../RecognizeEntitiesBatchDocuments.java | 5 +- .../RecognizeEntitiesBatchDocumentsAsync.java | 5 +- ...RecognizeLinkedEntitiesBatchDocuments.java | 5 +- ...nizeLinkedEntitiesBatchDocumentsAsync.java | 5 +- .../batch/RecognizePiiBatchDocuments.java | 5 +- .../RecognizePiiBatchDocumentsAsync.java | 5 +- .../TextAnalyticsAsyncClientTest.java | 145 +++++++++++++++++ .../TextAnalyticsClientTest.java | 152 ++++++++++++++++++ .../TextAnalyticsClientTestBase.java | 36 +++++ .../session-records/defaultPipeline.json | 26 +++ .../resources/session-records/invalidKey.json | 20 +++ .../session-records/missingEndpoint.json | 4 + .../session-records/nullAADCredential.json | 4 + .../session-records/nullServiceVersion.json | 26 +++ .../session-records/nullSubscriptionKey.json | 4 + .../session-records/updateToInvalidKey.json | 20 +++ .../session-records/updateToValidKey.json | 26 +++ .../resources/session-records/validKey.json | 26 +++ 47 files changed, 891 insertions(+), 113 deletions(-) create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/implementation/SubscriptionKeyCredentialPolicy.java create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/TextAnalyticsApiKeyCredential.java create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RotateSubscriptionKey.java create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RotateSubscriptionKeyAsync.java create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/defaultPipeline.json create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/invalidKey.json create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/missingEndpoint.json create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/nullAADCredential.json create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/nullServiceVersion.json create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/nullSubscriptionKey.json create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/updateToInvalidKey.json create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/updateToValidKey.json create mode 100644 sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/validKey.json 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 84d54d103508..f820cb0eb3f0 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 @@ -245,11 +245,12 @@ - + + diff --git a/sdk/textanalytics/azure-ai-textanalytics/README.md b/sdk/textanalytics/azure-ai-textanalytics/README.md index f0bb050eebc1..7efddbb369c9 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/README.md +++ b/sdk/textanalytics/azure-ai-textanalytics/README.md @@ -73,11 +73,11 @@ cognitive services. ``` Use the key as the credential parameter to authenticate the client: - + ```java TextAnalyticsClient textAnalyticsClient = new TextAnalyticsClientBuilder() - .subscriptionKey(SUBSCRIPTION_KEY) - .endpoint(ENDPOINT) + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); ``` @@ -100,10 +100,10 @@ cognitive services. AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET Use the returned token credential to authenticate the client: - + ```java TextAnalyticsAsyncClient textAnalyticsClient = new TextAnalyticsClientBuilder() - .endpoint(ENDPOINT) + .endpoint("{endpoint}") .credential(new DefaultAzureCredentialBuilder().build()) .buildAsyncClient(); ``` @@ -114,14 +114,27 @@ analyze sentiment, recognize entities, detect language, and extract key phrases To create a client object, you will need the cognitive services or text analytics endpoint to your resource and a subscription key that allows you access: - + ```java TextAnalyticsClient textAnalyticsClient = new TextAnalyticsClientBuilder() - .subscriptionKey(SUBSCRIPTION_KEY) - .endpoint(ENDPOINT) + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); ``` +#### Rotate existing subscription key +The Azure Text Analytics client library provide a way to rotate the existing subscription key. + + +```java +TextAnalyticsApiKeyCredential credential = new TextAnalyticsApiKeyCredential("{expired_subscription_key}"); +TextAnalyticsClient textAnalyticsClient = new TextAnalyticsClientBuilder() + .subscriptionKey(credential) + .endpoint("{endpoint}") + .buildClient(); + +credential.updateCredential("{new_subscription_key}"); +``` ## Key concepts ### Text Input @@ -186,23 +199,23 @@ The following sections provide several code snippets covering some of the most c Text analytics support both synchronous and asynchronous client creation by using `TextAnalyticsClientBuilder`, - + ``` java TextAnalyticsClient textAnalyticsClient = new TextAnalyticsClientBuilder() - .subscriptionKey(SUBSCRIPTION_KEY) - .endpoint(ENDPOINT) + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); ``` - + ``` java TextAnalyticsAsyncClient textAnalyticsClient = new TextAnalyticsClientBuilder() - .subscriptionKey(SUBSCRIPTION_KEY) - .endpoint(ENDPOINT) + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); ``` ### Detect language - + ```java String inputText = "Bonjour tout le monde"; @@ -215,7 +228,7 @@ for (DetectedLanguage detectedLanguage : textAnalyticsClient.detectLanguage(inpu ``` ### Recognize entity - + ```java String text = "Satya Nadella is the CEO of Microsoft"; @@ -230,7 +243,7 @@ for (NamedEntity entity : textAnalyticsClient.recognizeEntities(text).getNamedEn ``` ### Recognize PII(Personally Identifiable Information) entity - + ```java String text = "My SSN is 555-55-5555"; @@ -245,7 +258,7 @@ for (NamedEntity entity : textAnalyticsClient.recognizePiiEntities(text).getName ``` ### Recognize linked entity - + ```java String text = "Old Faithful is a geyser at Yellowstone Park."; @@ -258,7 +271,7 @@ for (LinkedEntity linkedEntity : textAnalyticsClient.recognizeLinkedEntities(tex } ``` ### Extract key phrases - + ```java String text = "My cat might need to see a veterinarian."; @@ -268,7 +281,7 @@ for (String keyPhrase : textAnalyticsClient.extractKeyPhrases(text).getKeyPhrase ``` ### Analyze sentiment - + ```java String text = "The hotel was dark and unclean."; @@ -285,8 +298,13 @@ Text Analytics clients raise exceptions. For example, if you try to detect the l document IDs, `400` error is return that indicating bad request. In the following code snippet, the error is handled gracefully by catching the exception and display the additional information about the error. - + ```java +List inputs = Arrays.asList( + new DetectLanguageInput("1", "This is written in English.", "us"), + new DetectLanguageInput("2", "Este es un document escrito en Español.", "es") +); + try { textAnalyticsClient.detectBatchLanguages(inputs); } catch (HttpResponseException e) { diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/TextAnalyticsClientBuilder.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/TextAnalyticsClientBuilder.java index ce06adc7650f..511e16ab0dd8 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/TextAnalyticsClientBuilder.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/TextAnalyticsClientBuilder.java @@ -3,8 +3,10 @@ package com.azure.ai.textanalytics; +import com.azure.ai.textanalytics.implementation.SubscriptionKeyCredentialPolicy; import com.azure.ai.textanalytics.implementation.TextAnalyticsClientImpl; import com.azure.ai.textanalytics.implementation.TextAnalyticsClientImplBuilder; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextAnalyticsClientOptions; import com.azure.core.annotation.ServiceClientBuilder; import com.azure.core.credential.TokenCredential; @@ -42,7 +44,8 @@ * *

* The client needs the service endpoint of the Azure Text Analytics to access the resource service. - * {@link #subscriptionKey(String) subscriptionKey(String)} or + * {@link #subscriptionKey(TextAnalyticsApiKeyCredential) + * subscriptionKey(TextAnalyticsApiKeyCredential)} or * {@link #credential(TokenCredential) credential(TokenCredential)} give the builder access credential. *

* @@ -74,7 +77,6 @@ public final class TextAnalyticsClientBuilder { private static final String CONTENT_TYPE_HEADER_VALUE = "application/json"; private static final String ACCEPT_HEADER = "Accept"; private static final String TEXT_ANALYTICS_PROPERTIES = "azure-ai-textanalytics.properties"; - private static final String OCP_APIM_SUBSCRIPTION_KEY = "Ocp-Apim-Subscription-Key"; private static final String NAME = "name"; private static final String VERSION = "version"; private static final RetryPolicy DEFAULT_RETRY_POLICY = new RetryPolicy("retry-after-ms", ChronoUnit.MILLIS); @@ -87,7 +89,7 @@ public final class TextAnalyticsClientBuilder { private final String clientVersion; private String endpoint; - private String subscriptionKey; + private TextAnalyticsApiKeyCredential credential; private TokenCredential tokenCredential; private HttpClient httpClient; private HttpLogOptions httpLogOptions; @@ -126,7 +128,7 @@ public TextAnalyticsClientBuilder() { * * @return A TextAnalyticsClient with the options set from the builder. * @throws NullPointerException if {@link #endpoint(String) endpoint} or - * {@link #subscriptionKey(String) subscriptionKey} has not been set. + * {@link #subscriptionKey(TextAnalyticsApiKeyCredential) subscriptionKey} has not been set. * @throws IllegalArgumentException if {@link #endpoint(String) endpoint} cannot be parsed into a valid URL. */ public TextAnalyticsClient buildClient() { @@ -146,7 +148,7 @@ public TextAnalyticsClient buildClient() { * * @return A TextAnalyticsAsyncClient with the options set from the builder. * @throws NullPointerException if {@link #endpoint(String) endpoint} or - * {@link #subscriptionKey(String) subscriptionKey} has not been set. + * {@link #subscriptionKey(TextAnalyticsApiKeyCredential) subscriptionKey} has not been set. * @throws IllegalArgumentException if {@link #endpoint(String) endpoint} cannot be parsed into a valid URL. */ public TextAnalyticsAsyncClient buildAsyncClient() { @@ -170,8 +172,8 @@ public TextAnalyticsAsyncClient buildAsyncClient() { if (tokenCredential != null) { // User token based policy policies.add(new BearerTokenAuthenticationPolicy(tokenCredential, DEFAULT_SCOPE)); - } else if (subscriptionKey != null) { - headers.put(OCP_APIM_SUBSCRIPTION_KEY, subscriptionKey); + } else if (credential != null) { + policies.add(new SubscriptionKeyCredentialPolicy(credential)); } else { // Throw exception that credential and tokenCredential cannot be null throw logger.logExceptionAsError( @@ -235,21 +237,28 @@ public TextAnalyticsClientBuilder endpoint(String endpoint) { } catch (MalformedURLException ex) { throw logger.logExceptionAsWarning(new IllegalArgumentException("'endpoint' must be a valid URL", ex)); } - this.endpoint = endpoint; + + if (endpoint.endsWith("/")) { + this.endpoint = endpoint.substring(0, endpoint.length() - 1); + } else { + this.endpoint = endpoint; + } + return this; } /** * Sets the credential to use when authenticating HTTP requests for this TextAnalyticsClientBuilder. * - * @param subscriptionKey subscription key + * @param subscriptionKeyCredential subscription key credential * * @return The updated TextAnalyticsClientBuilder object. - * @throws NullPointerException If {@code subscriptionKey} is {@code null} + * @throws NullPointerException If {@code subscriptionKeyCredential} is {@code null} */ - public TextAnalyticsClientBuilder subscriptionKey(String subscriptionKey) { - Objects.requireNonNull(subscriptionKey, "'subscriptionKey' cannot be null."); - this.subscriptionKey = subscriptionKey; + public TextAnalyticsClientBuilder subscriptionKey( + TextAnalyticsApiKeyCredential subscriptionKeyCredential) { + Objects.requireNonNull(subscriptionKeyCredential, "'subscriptionKeyCredential' cannot be null."); + this.credential = subscriptionKeyCredential; return this; } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/implementation/SubscriptionKeyCredentialPolicy.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/implementation/SubscriptionKeyCredentialPolicy.java new file mode 100644 index 000000000000..57622871780d --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/implementation/SubscriptionKeyCredentialPolicy.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.ai.textanalytics.implementation; + +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.ai.textanalytics.models.TextAnalyticsApiKeyCredential; +import reactor.core.publisher.Mono; + +/** + * Policy that adds the {@link TextAnalyticsApiKeyCredential} into the request's `Ocp-Apim-Subscription-Key` + * header. + */ +public final class SubscriptionKeyCredentialPolicy implements HttpPipelinePolicy { + private static final String OCP_APIM_SUBSCRIPTION_KEY = "Ocp-Apim-Subscription-Key"; + private final TextAnalyticsApiKeyCredential credential; + + /** + * Creates a {@link SubscriptionKeyCredentialPolicy} pipeline policy that adds the + * {@link TextAnalyticsApiKeyCredential} into the request's `Ocp-Apim-Subscription-Key` header. + * + * @param credential the {@link TextAnalyticsApiKeyCredential} credential used to create the policy. + */ + public SubscriptionKeyCredentialPolicy(TextAnalyticsApiKeyCredential credential) { + this.credential = credential; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + context.getHttpRequest().setHeader(OCP_APIM_SUBSCRIPTION_KEY, credential.getSubscriptionKey()); + return next.process(); + } +} diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/TextAnalyticsApiKeyCredential.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/TextAnalyticsApiKeyCredential.java new file mode 100644 index 000000000000..732ba68b8388 --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/TextAnalyticsApiKeyCredential.java @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.ai.textanalytics.models; + +import java.util.Objects; + +/** + * Subscription key credential that shared across cognitive services, or restrict to single service. + * + *

Be able to rotate an existing subscription key

+ * {@codesnippet com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential} + * + */ +public final class TextAnalyticsApiKeyCredential { + private volatile String subscriptionKey; + + /** + * Creates a {@link TextAnalyticsApiKeyCredential} model that describes subscription key for + * authentication. + * + * @param subscriptionKey the subscription key for authentication + */ + public TextAnalyticsApiKeyCredential(String subscriptionKey) { + this.subscriptionKey = Objects.requireNonNull(subscriptionKey, "`subscriptionKey` cannot be null."); + } + + /** + * Get the subscription key. + * + * @return the subscription key + */ + public String getSubscriptionKey() { + return this.subscriptionKey; + } + + /** + * Set the subscription key. + * + * @param subscriptionKey the subscription key for authentication + */ + public void updateCredential(String subscriptionKey) { + this.subscriptionKey = Objects.requireNonNull(subscriptionKey, "`subscriptionKey` cannot be null."); + } +} diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/README.md b/sdk/textanalytics/azure-ai-textanalytics/src/samples/README.md index 06f143efa846..f7ff96c2dd45 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/README.md +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/README.md @@ -21,21 +21,34 @@ Getting started explained in detail [here][SDK_README_GETTING_STARTED]. ## Examples The following sections provide several code snippets covering some of the most common configuration service tasks, including: -- [Detect language in text][sample_hello_world] +- [Detect language in text][sample_detect_language] +- [Detect language in text with asynchronous client][async_sample_detect_language] - [Recognize entities in text][sample_entities] +- [Recognize entities in text with asynchronous client][async_sample_entities] - [Recognize personally identifiable information in text][sample_pii_entities] +- [Recognize personally identifiable information in text with asynchronous client][async_sample_pii_entities] - [Recognize linked entities in text][sample_linked_entities] +- [Recognize linked entities in text with asynchronous client][async_sample_linked_entities] - [Extract key phrases in text][sample_key_phrases] -- [Analyze sentiment in text.][sample_sentiment] -- [Async Detect language in text][async_sample_hello_world] +- [Extract key phrases in text with asynchronous client][async_sample_key_phrases] +- [Analyze sentiment in text][sample_sentiment] +- [Analyze sentiment in text with asynchronous client][async_sample_sentiment] +- [Rotate subscription key][sample_rotate_key] +- [Rotate subscription key with asynchronous client][async_sample_rotate_key] Batch Samples: -- [Detect language for a batch of documents][sample_language_batch] +- [Detect language for a batch of documents][sample_detect_language_batch] +- [Detect language for a batch of documents with asynchronous client][async_sample_detect_language_batch] - [Recognize entities in a batch of documents][sample_entities_batch] +- [Recognize entities in a batch of documents with asynchronous client][async_sample_entities_batch] - [Recognize personally identifiable information in a batch of documents][sample_pii_entities_batch] +- [Recognize personally identifiable information in a batch of documents with asynchronous client][async_sample_pii_entities_batch] - [Recognize linked entities in a batch of documents][sample_linked_entities_batch] +- [Recognize linked entities in a batch of documents with asynchronous client][async_sample_linked_entities_batch] - [Extract key phrases in a batch of documents][sample_key_phrases_batch] +- [Extract key phrases in a batch of documents with asynchronous client][async_sample_key_phrases_batch] - [Analyze sentiment in a batch of documents][sample_sentiment_batch] +- [Analyze sentiment in a batch of documents with asynchronous client][async_sample_sentiment_batch] ## Troubleshooting Troubleshooting steps can be found [here][SDK_README_TROUBLESHOOTING]. @@ -56,19 +69,32 @@ Guidelines](../../CONTRIBUTING.md) for more information. [SDK_README_DEPENDENCY]: ../../README.md#adding-the-package-to-your-product [SDK_README_NEXT_STEPS]: ../../README.md#next-steps -[async_sample_hello_world]: java/com/azure/ai/textanalytics/DetectLanguageAsync.java -[sample_hello_world]: java/com/azure/ai/textanalytics/DetectLanguage.java -[sample_entities]: java/com/azure/ai/textanalytics/RecognizeEntities.java -[sample_pii_entities]: java/com/azure/ai/textanalytics/RecognizePii.java -[sample_linked_entities]: java/com/azure/ai/textanalytics/RecognizeLinkedEntities.java -[sample_key_phrases]: java/com/azure/ai/textanalytics/ExtractKeyPhrases.java -[sample_sentiment]: java/com/azure/ai/textanalytics/AnalyzeSentiment.java +[async_sample_detect_language]: java/com/azure/ai/textanalytics/DetectLanguageAsync.java +[async_sample_detect_language_batch]: java/com/azure/ai/textanalytics/batch/DetectLanguageBatchDocumentsAsync.java +[async_sample_entities]: java/com/azure/ai/textanalytics/RecognizeEntitiesAsync.java +[async_sample_entities_batch]: java/com/azure/ai/textanalytics/batch/RecognizeEntitiesBatchDocumentsAsync.java +[async_sample_linked_entities]: java/com/azure/ai/textanalytics/RecognizeLinkedEntitiesAsync.java +[async_sample_linked_entities_batch]: java/com/azure/ai/textanalytics/batch/RecognizeLinkedEntitiesBatchDocumentsAsync.java +[async_sample_key_phrases]: java/com/azure/ai/textanalytics/ExtractKeyPhrasesAsync.java +[async_sample_key_phrases_batch]: java/com/azure/ai/textanalytics/batch/ExtractKeyPhrasesBatchDocumentsAsync.java +[async_sample_pii_entities]: java/com/azure/ai/textanalytics/RecognizePiiAsync.java +[async_sample_pii_entities_batch]: java/com/azure/ai/textanalytics/batch/RecognizePiiBatchDocumentsAsync.java +[async_sample_rotate_key]: java/com/azure/ai/textanalytics/RotateSubscriptionKeyAsync.java +[async_sample_sentiment]: java/com/azure/ai/textanalytics/AnalyzeSentimentAsync.java +[async_sample_sentiment_batch]: java/com/azure/ai/textanalytics/batch/AnalyzeSentimentBatchDocumentsAsync.java -[sample_language_batch]: java/com/azure/ai/textanalytics/batch/DetectLanguageBatchDocuments.java +[sample_detect_language]: java/com/azure/ai/textanalytics/DetectLanguage.java +[sample_detect_language_batch]: java/com/azure/ai/textanalytics/batch/DetectLanguageBatchDocuments.java +[sample_entities]: java/com/azure/ai/textanalytics/RecognizeEntities.java [sample_entities_batch]: java/com/azure/ai/textanalytics/batch/RecognizeEntitiesBatchDocuments.java -[sample_pii_entities_batch]: java/com/azure/ai/textanalytics/batch/RecognizePiiBatchDocuments.java +[sample_linked_entities]: java/com/azure/ai/textanalytics/RecognizeLinkedEntities.java [sample_linked_entities_batch]: java/com/azure/ai/textanalytics/batch/RecognizeLinkedEntitiesBatchDocuments.java +[sample_key_phrases]: java/com/azure/ai/textanalytics/ExtractKeyPhrases.java [sample_key_phrases_batch]: java/com/azure/ai/textanalytics/batch/ExtractKeyPhrasesBatchDocuments.java +[sample_pii_entities]: java/com/azure/ai/textanalytics/RecognizePii.java +[sample_pii_entities_batch]: java/com/azure/ai/textanalytics/batch/RecognizePiiBatchDocuments.java +[sample_rotate_key]: java/com/azure/ai/textanalytics/RotateSubscriptionKey.java +[sample_sentiment]: java/com/azure/ai/textanalytics/AnalyzeSentiment.java [sample_sentiment_batch]: java/com/azure/ai/textanalytics/batch/AnalyzeSentimentBatchDocuments.java ![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-java%2Fsdk%2Ftextanalytics%2Fazure-ai-textanalytics%2FREADME.png) diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/AnalyzeSentiment.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/AnalyzeSentiment.java index 33c55e930677..41afb635083b 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/AnalyzeSentiment.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/AnalyzeSentiment.java @@ -3,6 +3,7 @@ package com.azure.ai.textanalytics; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextSentiment; import com.azure.ai.textanalytics.models.AnalyzeSentimentResult; @@ -18,8 +19,8 @@ public class AnalyzeSentiment { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // The text that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/AnalyzeSentimentAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/AnalyzeSentimentAsync.java index fcb636891ac4..84f42c53edfb 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/AnalyzeSentimentAsync.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/AnalyzeSentimentAsync.java @@ -3,6 +3,7 @@ package com.azure.ai.textanalytics; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextSentiment; import java.util.concurrent.TimeUnit; @@ -19,8 +20,8 @@ public class AnalyzeSentimentAsync { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // The text that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/DetectLanguage.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/DetectLanguage.java index 9bdfa281010d..71da0b4fb847 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/DetectLanguage.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/DetectLanguage.java @@ -5,6 +5,7 @@ import com.azure.ai.textanalytics.models.DetectLanguageResult; import com.azure.ai.textanalytics.models.DetectedLanguage; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; /** * Sample demonstrates how to detect the language of an input text. @@ -18,8 +19,8 @@ public class DetectLanguage { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // The text that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/DetectLanguageAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/DetectLanguageAsync.java index a1dc376928d1..dae75fa4b940 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/DetectLanguageAsync.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/DetectLanguageAsync.java @@ -4,6 +4,7 @@ package com.azure.ai.textanalytics; import com.azure.ai.textanalytics.models.DetectedLanguage; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import java.util.concurrent.TimeUnit; @@ -19,8 +20,8 @@ public class DetectLanguageAsync { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // The text that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/ExtractKeyPhrases.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/ExtractKeyPhrases.java index 23d752ac72ee..d49bccf492a6 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/ExtractKeyPhrases.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/ExtractKeyPhrases.java @@ -3,6 +3,8 @@ package com.azure.ai.textanalytics; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; + /** * Sample demonstrates how to extract the key phrases of an input text. */ @@ -15,8 +17,8 @@ public class ExtractKeyPhrases { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // The text that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/ExtractKeyPhrasesAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/ExtractKeyPhrasesAsync.java index 8049c2bf4c6c..29dac5584293 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/ExtractKeyPhrasesAsync.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/ExtractKeyPhrasesAsync.java @@ -3,6 +3,8 @@ package com.azure.ai.textanalytics; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; + import java.util.concurrent.TimeUnit; /** @@ -17,8 +19,8 @@ public class ExtractKeyPhrasesAsync { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // The text that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/ReadmeSamples.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/ReadmeSamples.java index df946f34384b..0e71621bdde4 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/ReadmeSamples.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/ReadmeSamples.java @@ -7,6 +7,7 @@ import com.azure.ai.textanalytics.models.DetectedLanguage; import com.azure.ai.textanalytics.models.LinkedEntity; import com.azure.ai.textanalytics.models.NamedEntity; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextSentiment; import com.azure.core.exception.HttpResponseException; import com.azure.core.http.HttpClient; @@ -24,8 +25,6 @@ * Class containing code snippets that will be injected to README.md. */ public class ReadmeSamples { - private static final String SUBSCRIPTION_KEY = null; - private static final String ENDPOINT = null; private TextAnalyticsClient textAnalyticsClient = new TextAnalyticsClientBuilder().buildClient(); /** @@ -43,8 +42,8 @@ public void configureHttpClient() { */ public void useSubscriptionKeySyncClient() { TextAnalyticsClient textAnalyticsClient = new TextAnalyticsClientBuilder() - .subscriptionKey(SUBSCRIPTION_KEY) - .endpoint(ENDPOINT) + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); } @@ -53,8 +52,8 @@ public void useSubscriptionKeySyncClient() { */ public void useSubscriptionKeyAsyncClient() { TextAnalyticsAsyncClient textAnalyticsClient = new TextAnalyticsClientBuilder() - .subscriptionKey(SUBSCRIPTION_KEY) - .endpoint(ENDPOINT) + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); } @@ -63,7 +62,7 @@ public void useSubscriptionKeyAsyncClient() { */ public void useAadAsyncClient() { TextAnalyticsAsyncClient textAnalyticsClient = new TextAnalyticsClientBuilder() - .endpoint(ENDPOINT) + .endpoint("{endpoint}") .credential(new DefaultAzureCredentialBuilder().build()) .buildAsyncClient(); } @@ -167,4 +166,17 @@ public void handlingException() { System.out.println(e.getMessage()); } } + + /** + * Code snippet for rotating subscription key of the client + */ + public void rotatingSubscriptionKey() { + TextAnalyticsApiKeyCredential credential = new TextAnalyticsApiKeyCredential("{expired_subscription_key}"); + TextAnalyticsClient textAnalyticsClient = new TextAnalyticsClientBuilder() + .subscriptionKey(credential) + .endpoint("{endpoint}") + .buildClient(); + + credential.updateCredential("{new_subscription_key}"); + } } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeEntities.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeEntities.java index f0d940a35680..8092c16c70ed 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeEntities.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeEntities.java @@ -4,6 +4,7 @@ package com.azure.ai.textanalytics; import com.azure.ai.textanalytics.models.NamedEntity; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; /** * Sample demonstrates how to recognize the entities of an input text. @@ -17,8 +18,8 @@ public class RecognizeEntities { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // The text that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeEntitiesAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeEntitiesAsync.java index 9e831c43611c..1ab6f19bef32 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeEntitiesAsync.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeEntitiesAsync.java @@ -4,6 +4,7 @@ package com.azure.ai.textanalytics; import com.azure.ai.textanalytics.models.NamedEntity; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import java.util.concurrent.TimeUnit; @@ -19,8 +20,8 @@ public class RecognizeEntitiesAsync { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // The text that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeLinkedEntities.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeLinkedEntities.java index 9e01255b55ae..55b72f9d80de 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeLinkedEntities.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeLinkedEntities.java @@ -4,6 +4,7 @@ package com.azure.ai.textanalytics; import com.azure.ai.textanalytics.models.LinkedEntity; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; /** * Sample demonstrates how to recognize the linked entities of an input text. @@ -17,8 +18,8 @@ public class RecognizeLinkedEntities { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // The text that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeLinkedEntitiesAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeLinkedEntitiesAsync.java index c10c3b800f83..5eb0a21b39ae 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeLinkedEntitiesAsync.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizeLinkedEntitiesAsync.java @@ -4,6 +4,7 @@ package com.azure.ai.textanalytics; import com.azure.ai.textanalytics.models.LinkedEntity; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import java.util.concurrent.TimeUnit; @@ -19,8 +20,8 @@ public class RecognizeLinkedEntitiesAsync { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // The text that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizePii.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizePii.java index 71cc78bd856f..dc9dd4c2ce2f 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizePii.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizePii.java @@ -4,6 +4,7 @@ package com.azure.ai.textanalytics; import com.azure.ai.textanalytics.models.NamedEntity; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; /** * Sample demonstrates how to recognize the PII(Personally Identifiable Information) entities of an input text. @@ -17,8 +18,8 @@ public class RecognizePii { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // The text that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizePiiAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizePiiAsync.java index 3186b57f3cf9..1dfa32ee22c5 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizePiiAsync.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RecognizePiiAsync.java @@ -4,6 +4,7 @@ package com.azure.ai.textanalytics; import com.azure.ai.textanalytics.models.NamedEntity; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import java.util.concurrent.TimeUnit; @@ -20,8 +21,8 @@ public class RecognizePiiAsync { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // The text that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RotateSubscriptionKey.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RotateSubscriptionKey.java new file mode 100644 index 000000000000..8b04eed6536a --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RotateSubscriptionKey.java @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.ai.textanalytics; + +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; +import com.azure.core.exception.HttpResponseException; + +/** + * Sample demonstrates how to rotate the existing subscription key of text analytics client + */ +public class RotateSubscriptionKey { + + /** + * Main method to invoke this demo about how to rotate the existing subscription key of text analytics client. + * + * @param args Unused arguments to the program. + */ + public static void main(String[] args) { + TextAnalyticsApiKeyCredential credential = new TextAnalyticsApiKeyCredential("{invalid_subscription_key}"); + TextAnalyticsClient client = new TextAnalyticsClientBuilder() + .subscriptionKey(credential) + .endpoint("{endpoint}") + .buildClient(); + + // The text that need be analysed. + String text = "My cat might need to see a veterinarian."; + + try { + client.extractKeyPhrases(text); + } catch (HttpResponseException ex) { + System.out.println(ex.getMessage()); + } + + // Update the subscription key + credential.updateCredential("{valid_subscription_key}"); + + for (String keyPhrase : client.extractKeyPhrases(text).getKeyPhrases()) { + System.out.printf("Recognized phrases: %s.%n", keyPhrase); + } + } +} diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RotateSubscriptionKeyAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RotateSubscriptionKeyAsync.java new file mode 100644 index 000000000000..4a0ab07e8246 --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/RotateSubscriptionKeyAsync.java @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.ai.textanalytics; + +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; + +import java.util.concurrent.TimeUnit; + +/** + * Sample demonstrates how to rotate the existing subscription key of text analytics client + */ +public class RotateSubscriptionKeyAsync { + + /** + * Main method to invoke this demo about how to rotate the existing subscription key of text analytics client. + * + * @param args Unused arguments to the program. + */ + public static void main(String[] args) { + TextAnalyticsApiKeyCredential credential = new TextAnalyticsApiKeyCredential("{invalid_subscription_key}"); + TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() + .subscriptionKey(credential) + .endpoint("{endpoint}") + .buildAsyncClient(); + + // The text that need be analysed. + String text = "My cat might need to see a veterinarian."; + + client.extractKeyPhrases(text).subscribe( + result -> { + for (String keyPhrase : result.getKeyPhrases()) { + System.out.printf("Recognized phrases: %s.%n", keyPhrase); + } + }, + error -> System.err.println("There was an error extracting key phrases of the text." + error), + () -> System.out.println("Key phrases extracted.")); + + // Update the subscription key + credential.updateCredential("{valid_subscription_key}"); + + client.extractKeyPhrases(text).subscribe( + result -> { + for (String keyPhrase : result.getKeyPhrases()) { + System.out.printf("Recognized phrases: %s.%n", keyPhrase); + } + }, + error -> System.err.println("There was an error extracting key phrases of the text." + error), + () -> System.out.println("Key phrases extracted.")); + + // The .subscribe() creation and assignment is not a blocking call. For the purpose of this example, we sleep + // the thread so the program does not end before the send operation is complete. Using .block() instead of + // .subscribe() will turn this into a synchronous call. + try { + TimeUnit.SECONDS.sleep(5); + } catch (InterruptedException ignored) { + } + } +} diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClientJavaDocCodeSnippets.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClientJavaDocCodeSnippets.java index 7a13f73091ac..cf7a158a5195 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClientJavaDocCodeSnippets.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClientJavaDocCodeSnippets.java @@ -15,6 +15,7 @@ import com.azure.ai.textanalytics.models.RecognizeLinkedEntitiesResult; import com.azure.ai.textanalytics.models.RecognizePiiEntitiesResult; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; import com.azure.ai.textanalytics.models.TextSentiment; @@ -26,8 +27,6 @@ * Code snippet for {@link TextAnalyticsAsyncClient} */ public class TextAnalyticsAsyncClientJavaDocCodeSnippets { - private static final String SUBSCRIPTION_KEY = null; - private static final String ENDPOINT = null; TextAnalyticsAsyncClient textAnalyticsAsyncClient = createTextAnalyticsAsyncClient(); /** @@ -38,13 +37,30 @@ public class TextAnalyticsAsyncClientJavaDocCodeSnippets { public TextAnalyticsAsyncClient createTextAnalyticsAsyncClient() { // BEGIN: com.azure.ai.textanalytics.TextAnalyticsAsyncClient.instantiation TextAnalyticsAsyncClient textAnalyticsAsyncClient = new TextAnalyticsClientBuilder() - .subscriptionKey(SUBSCRIPTION_KEY) - .endpoint(ENDPOINT) + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // END: com.azure.ai.textanalytics.TextAnalyticsAsyncClient.instantiation return textAnalyticsAsyncClient; } + /** + * Code snippet for updating the existing subscription key. + */ + public void rotateSubscriptionKey() { + // BEGIN: com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential + TextAnalyticsApiKeyCredential credential = + new TextAnalyticsApiKeyCredential("{subscription_key}"); + + TextAnalyticsAsyncClient textAnalyticsAsyncClient = new TextAnalyticsClientBuilder() + .subscriptionKey(credential) + .endpoint("{endpoint}") + .buildAsyncClient(); + + credential.updateCredential("{new_subscription_key}"); + // END: com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential + } + // Languages /** * Code snippet for {@link TextAnalyticsAsyncClient#detectLanguage(String)} diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/TextAnalyticsClientJavaDocCodeSnippets.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/TextAnalyticsClientJavaDocCodeSnippets.java index e823717dadf2..98182ffcf4da 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/TextAnalyticsClientJavaDocCodeSnippets.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/TextAnalyticsClientJavaDocCodeSnippets.java @@ -15,6 +15,7 @@ import com.azure.ai.textanalytics.models.RecognizeLinkedEntitiesResult; import com.azure.ai.textanalytics.models.RecognizePiiEntitiesResult; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; import com.azure.ai.textanalytics.models.TextSentiment; @@ -29,8 +30,6 @@ * Code snippets for {@link TextAnalyticsClient} and {@link TextAnalyticsClientBuilder} */ public class TextAnalyticsClientJavaDocCodeSnippets { - private static final String SUBSCRIPTION_KEY = null; - private static final String ENDPOINT = null; private final TextAnalyticsClient textAnalyticsClient = new TextAnalyticsClientBuilder().buildClient(); /** @@ -43,9 +42,9 @@ public void createTextAnalyticsClientWithPipeline() { .build(); TextAnalyticsClient textAnalyticsClient = new TextAnalyticsClientBuilder() + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .pipeline(pipeline) - .endpoint(ENDPOINT) - .subscriptionKey(SUBSCRIPTION_KEY) .buildClient(); // END: com.azure.ai.textanalytics.TextAnalyticsClient.pipeline.instantiation } @@ -56,8 +55,8 @@ public void createTextAnalyticsClientWithPipeline() { public void createTextAnalyticsClient() { // BEGIN: com.azure.ai.textanalytics.TextAnalyticsClient.instantiation TextAnalyticsClient textAnalyticsClient = new TextAnalyticsClientBuilder() - .subscriptionKey(SUBSCRIPTION_KEY) - .endpoint(ENDPOINT) + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // END: com.azure.ai.textanalytics.TextAnalyticsClient.instantiation } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/AnalyzeSentimentBatchDocuments.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/AnalyzeSentimentBatchDocuments.java index 80a1b5fbbe61..b906da6c9a88 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/AnalyzeSentimentBatchDocuments.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/AnalyzeSentimentBatchDocuments.java @@ -7,6 +7,7 @@ import com.azure.ai.textanalytics.TextAnalyticsClientBuilder; import com.azure.ai.textanalytics.models.DocumentResultCollection; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; import com.azure.ai.textanalytics.models.TextSentiment; @@ -28,8 +29,8 @@ public class AnalyzeSentimentBatchDocuments { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // The texts that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/AnalyzeSentimentBatchDocumentsAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/AnalyzeSentimentBatchDocumentsAsync.java index cc7b8983c432..e7b38e0f11c0 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/AnalyzeSentimentBatchDocumentsAsync.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/AnalyzeSentimentBatchDocumentsAsync.java @@ -8,6 +8,7 @@ import com.azure.ai.textanalytics.models.AnalyzeSentimentResult; import com.azure.ai.textanalytics.models.DocumentResultCollection; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; import com.azure.ai.textanalytics.models.TextSentiment; @@ -28,8 +29,8 @@ public class AnalyzeSentimentBatchDocumentsAsync { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // The texts that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/DetectLanguageBatchDocuments.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/DetectLanguageBatchDocuments.java index 48574f724ca9..0d5055133dd3 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/DetectLanguageBatchDocuments.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/DetectLanguageBatchDocuments.java @@ -10,6 +10,7 @@ import com.azure.ai.textanalytics.models.DetectedLanguage; import com.azure.ai.textanalytics.models.DocumentResultCollection; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.core.util.Context; @@ -28,8 +29,8 @@ public class DetectLanguageBatchDocuments { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // The texts that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/DetectLanguageBatchDocumentsAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/DetectLanguageBatchDocumentsAsync.java index e52f2b859489..3881f376e3d0 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/DetectLanguageBatchDocumentsAsync.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/DetectLanguageBatchDocumentsAsync.java @@ -10,6 +10,7 @@ import com.azure.ai.textanalytics.models.DetectedLanguage; import com.azure.ai.textanalytics.models.DocumentResultCollection; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import java.util.Arrays; @@ -28,8 +29,8 @@ public class DetectLanguageBatchDocumentsAsync { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // The texts that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/ExtractKeyPhrasesBatchDocuments.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/ExtractKeyPhrasesBatchDocuments.java index 8af363673984..f3f06017169a 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/ExtractKeyPhrasesBatchDocuments.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/ExtractKeyPhrasesBatchDocuments.java @@ -8,6 +8,7 @@ import com.azure.ai.textanalytics.models.DocumentResultCollection; import com.azure.ai.textanalytics.models.ExtractKeyPhraseResult; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; import com.azure.core.util.Context; @@ -27,8 +28,8 @@ public class ExtractKeyPhrasesBatchDocuments { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // The texts that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/ExtractKeyPhrasesBatchDocumentsAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/ExtractKeyPhrasesBatchDocumentsAsync.java index 4991b96c8cd4..4de715dfaba4 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/ExtractKeyPhrasesBatchDocumentsAsync.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/ExtractKeyPhrasesBatchDocumentsAsync.java @@ -8,6 +8,7 @@ import com.azure.ai.textanalytics.models.DocumentResultCollection; import com.azure.ai.textanalytics.models.ExtractKeyPhraseResult; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; @@ -27,8 +28,8 @@ public class ExtractKeyPhrasesBatchDocumentsAsync { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // The texts that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeEntitiesBatchDocuments.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeEntitiesBatchDocuments.java index 25c396359524..a774630d7564 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeEntitiesBatchDocuments.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeEntitiesBatchDocuments.java @@ -9,6 +9,7 @@ import com.azure.ai.textanalytics.models.NamedEntity; import com.azure.ai.textanalytics.models.RecognizeEntitiesResult; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; import com.azure.core.util.Context; @@ -28,8 +29,8 @@ public class RecognizeEntitiesBatchDocuments { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // The texts that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeEntitiesBatchDocumentsAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeEntitiesBatchDocumentsAsync.java index 3a39d1a21314..fb3afa58a4a9 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeEntitiesBatchDocumentsAsync.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeEntitiesBatchDocumentsAsync.java @@ -9,6 +9,7 @@ import com.azure.ai.textanalytics.models.NamedEntity; import com.azure.ai.textanalytics.models.RecognizeEntitiesResult; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; @@ -28,8 +29,8 @@ public class RecognizeEntitiesBatchDocumentsAsync { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // The texts that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeLinkedEntitiesBatchDocuments.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeLinkedEntitiesBatchDocuments.java index bc85a0b36a8e..a3435fa709e7 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeLinkedEntitiesBatchDocuments.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeLinkedEntitiesBatchDocuments.java @@ -9,6 +9,7 @@ import com.azure.ai.textanalytics.models.LinkedEntity; import com.azure.ai.textanalytics.models.RecognizeLinkedEntitiesResult; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; import com.azure.core.util.Context; @@ -28,8 +29,8 @@ public class RecognizeLinkedEntitiesBatchDocuments { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // The texts that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeLinkedEntitiesBatchDocumentsAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeLinkedEntitiesBatchDocumentsAsync.java index 4b6038a093cf..390e2cbd0197 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeLinkedEntitiesBatchDocumentsAsync.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizeLinkedEntitiesBatchDocumentsAsync.java @@ -9,6 +9,7 @@ import com.azure.ai.textanalytics.models.LinkedEntity; import com.azure.ai.textanalytics.models.RecognizeLinkedEntitiesResult; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; @@ -28,8 +29,8 @@ public class RecognizeLinkedEntitiesBatchDocumentsAsync { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // The texts that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizePiiBatchDocuments.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizePiiBatchDocuments.java index edf4b38b63f4..4ad287594b68 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizePiiBatchDocuments.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizePiiBatchDocuments.java @@ -9,6 +9,7 @@ import com.azure.ai.textanalytics.models.NamedEntity; import com.azure.ai.textanalytics.models.RecognizePiiEntitiesResult; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; import com.azure.core.util.Context; @@ -28,8 +29,8 @@ public class RecognizePiiBatchDocuments { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildClient(); // The texts that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizePiiBatchDocumentsAsync.java b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizePiiBatchDocumentsAsync.java index e38983e2e7d6..17dc93346c86 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizePiiBatchDocumentsAsync.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/samples/java/com/azure/ai/textanalytics/batch/RecognizePiiBatchDocumentsAsync.java @@ -9,6 +9,7 @@ import com.azure.ai.textanalytics.models.NamedEntity; import com.azure.ai.textanalytics.models.RecognizePiiEntitiesResult; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; @@ -29,8 +30,8 @@ public class RecognizePiiBatchDocumentsAsync { public static void main(String[] args) { // Instantiate a client that will be used to call the service. TextAnalyticsAsyncClient client = new TextAnalyticsClientBuilder() - .subscriptionKey("{subscription_key}") - .endpoint("https://{servicename}.cognitiveservices.azure.com/") + .subscriptionKey(new TextAnalyticsApiKeyCredential("{subscription_key}")) + .endpoint("{endpoint}") .buildAsyncClient(); // The texts that need be analysed. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClientTest.java b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClientTest.java index 5870660a2902..e48398aa4b20 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClientTest.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClientTest.java @@ -11,9 +11,15 @@ import com.azure.ai.textanalytics.models.RecognizeEntitiesResult; import com.azure.ai.textanalytics.models.RecognizeLinkedEntitiesResult; import com.azure.ai.textanalytics.models.TextAnalyticsError; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextSentiment; import com.azure.ai.textanalytics.models.TextSentimentClass; import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.netty.NettyAsyncHttpClientBuilder; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.util.Configuration; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -31,6 +37,7 @@ import static com.azure.ai.textanalytics.TestUtils.getExpectedBatchPiiEntities; import static com.azure.ai.textanalytics.TestUtils.getExpectedBatchTextSentiment; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class TextAnalyticsAsyncClientTest extends TextAnalyticsClientTestBase { private TextAnalyticsAsyncClient client; @@ -475,4 +482,142 @@ public void analyseSentimentForBatchInputShowStatistics() { .assertNext(response -> validateSentiment(true, getExpectedBatchTextSentiment(), response.getValue())) .verifyComplete()); } + + /** + * Test client builder with valid subscription key + */ + @Test + public void validKey() { + // Arrange + final TextAnalyticsAsyncClient client = createClientBuilder(getEndpoint(), + new TextAnalyticsApiKeyCredential(getSubscriptionKey())).buildAsyncClient(); + + // Action and Assert + StepVerifier.create(client.detectLanguage("This is a test English Text")) + .assertNext(response -> validateDetectedLanguages( + Arrays.asList(new DetectedLanguage("English", "en", 1.0)), + response.getDetectedLanguages())) + .verifyComplete(); + } + + /** + * Test client builder with invalid subscription key + */ + @Test + public void invalidKey() { + // Arrange + final TextAnalyticsAsyncClient client = createClientBuilder(getEndpoint(), + new TextAnalyticsApiKeyCredential(INVALID_KEY)).buildAsyncClient(); + + // Action and Assert + StepVerifier.create(client.detectLanguage("This is a test English Text")) + .verifyError(HttpResponseException.class); + } + + /** + * Test client with valid subscription key but update to invalid key and make call to server. + */ + @Test + public void updateToInvalidKey() { + // Arrange + final TextAnalyticsApiKeyCredential credential = + new TextAnalyticsApiKeyCredential(getSubscriptionKey()); + + final TextAnalyticsAsyncClient client = createClientBuilder(getEndpoint(), credential).buildAsyncClient(); + + // Update to invalid key + credential.updateCredential(INVALID_KEY); + + // Action and Assert + StepVerifier.create(client.detectLanguage("This is a test English Text")) + .verifyError(HttpResponseException.class); + } + + /** + * Test client with invalid subscription key but update to valid key and make call to server. + */ + @Test + public void updateToValidKey() { + // Arrange + final TextAnalyticsApiKeyCredential credential = + new TextAnalyticsApiKeyCredential(INVALID_KEY); + + final TextAnalyticsAsyncClient client = createClientBuilder(getEndpoint(), credential).buildAsyncClient(); + + // Update to valid key + credential.updateCredential(getSubscriptionKey()); + + // Action and Assert + StepVerifier.create(client.detectLanguage("This is a test English Text")) + .assertNext(response -> validateDetectedLanguages( + Arrays.asList(new DetectedLanguage("English", "en", 1.0)), + response.getDetectedLanguages())) + .verifyComplete(); + } + + /** + * Test for missing endpoint + */ + @Test + public void missingEndpoint() { + assertThrows(NullPointerException.class, () -> { + final TextAnalyticsClientBuilder builder = new TextAnalyticsClientBuilder(); + builder.buildAsyncClient(); + }); + } + + /** + * Test for null service version, which would take take the default service version by default + */ + @Test + public void nullServiceVersion() { + // Arrange + final TextAnalyticsClientBuilder clientBuilder = new TextAnalyticsClientBuilder() + .endpoint(getEndpoint()) + .subscriptionKey(new TextAnalyticsApiKeyCredential(getSubscriptionKey())) + .retryPolicy(new RetryPolicy()) + .httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS)) + .serviceVersion(null); + + if (interceptorManager.isPlaybackMode()) { + clientBuilder.httpClient(interceptorManager.getPlaybackClient()); + } else { + clientBuilder.httpClient(new NettyAsyncHttpClientBuilder().wiretap(true).build()) + .addPolicy(interceptorManager.getRecordPolicy()); + } + + // Action and Assert + StepVerifier.create(clientBuilder.buildAsyncClient().detectLanguage("This is a test English Text")) + .assertNext(response -> validateDetectedLanguages( + Arrays.asList(new DetectedLanguage("English", "en", 1.0)), + response.getDetectedLanguages())) + .verifyComplete(); + } + + /** + * Test for default pipeline in client builder + */ + @Test + public void defaultPipeline() { + // Arrange + final TextAnalyticsClientBuilder clientBuilder = new TextAnalyticsClientBuilder() + .endpoint(getEndpoint()) + .subscriptionKey(new TextAnalyticsApiKeyCredential(getSubscriptionKey())) + .configuration(Configuration.getGlobalConfiguration()) + .httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS)); + + if (interceptorManager.isPlaybackMode()) { + clientBuilder.httpClient(interceptorManager.getPlaybackClient()); + } else { + clientBuilder.httpClient(new NettyAsyncHttpClientBuilder().wiretap(true).build()) + .addPolicy(interceptorManager.getRecordPolicy()); + } + + // Action and Assert + StepVerifier.create(clientBuilder.buildAsyncClient().detectLanguage("This is a test English Text")) + .assertNext(response -> validateDetectedLanguages( + Arrays.asList(new DetectedLanguage("English", "en", 1.0)), + response.getDetectedLanguages())) + .verifyComplete(); + } } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsClientTest.java b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsClientTest.java index ce92afce7d67..b8654d91b92b 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsClientTest.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsClientTest.java @@ -13,9 +13,15 @@ import com.azure.ai.textanalytics.models.RecognizeEntitiesResult; import com.azure.ai.textanalytics.models.RecognizeLinkedEntitiesResult; import com.azure.ai.textanalytics.models.TextAnalyticsError; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextSentiment; import com.azure.ai.textanalytics.models.TextSentimentClass; import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.netty.NettyAsyncHttpClientBuilder; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.util.Configuration; import com.azure.core.util.Context; import org.junit.jupiter.api.Test; @@ -408,4 +414,150 @@ public void analyseSentimentForBatchInputShowStatistics() { validateSentiment(true, getExpectedBatchTextSentiment(), client.analyzeBatchSentimentWithResponse(inputs, options, Context.NONE).getValue())); } + + /** + * Test client builder with valid subscription key + */ + @Test + public void validKey() { + // Arrange + final TextAnalyticsClient client = createClientBuilder(getEndpoint(), + new TextAnalyticsApiKeyCredential(getSubscriptionKey())).buildClient(); + + // Action and Assert + validateDetectedLanguages(Arrays.asList(new DetectedLanguage("English", "en", 1.0)), + client.detectLanguage("This is a test English Text").getDetectedLanguages()); + } + + /** + * Test client builder with invalid subscription key + */ + @Test + public void invalidKey() { + // Arrange + final TextAnalyticsClient client = createClientBuilder(getEndpoint(), + new TextAnalyticsApiKeyCredential(INVALID_KEY)).buildClient(); + + // Action and Assert + assertThrows(HttpResponseException.class, () -> client.detectLanguage("This is a test English Text")); + } + + /** + * Test client with valid subscription key but update to invalid key and make call to server. + */ + @Test + public void updateToInvalidKey() { + // Arrange + final TextAnalyticsApiKeyCredential credential = + new TextAnalyticsApiKeyCredential(getSubscriptionKey()); + + final TextAnalyticsClient client = createClientBuilder(getEndpoint(), credential).buildClient(); + + // Update to invalid key + credential.updateCredential(INVALID_KEY); + + // Action and Assert + assertThrows(HttpResponseException.class, () -> client.detectLanguage("This is a test English Text")); + } + + /** + * Test client with invalid subscription key but update to valid key and make call to server. + */ + @Test + public void updateToValidKey() { + // Arrange + final TextAnalyticsApiKeyCredential credential = + new TextAnalyticsApiKeyCredential(INVALID_KEY); + + final TextAnalyticsClient client = createClientBuilder(getEndpoint(), credential).buildClient(); + + // Update to valid key + credential.updateCredential(getSubscriptionKey()); + + // Action and Assert + validateDetectedLanguages(Arrays.asList(new DetectedLanguage("English", "en", 1.0)), + client.detectLanguage("This is a test English Text").getDetectedLanguages()); + } + + /** + * Test for missing endpoint + */ + @Test + public void missingEndpoint() { + assertThrows(NullPointerException.class, () -> { + final TextAnalyticsClientBuilder builder = new TextAnalyticsClientBuilder(); + builder.buildClient(); + }); + } + + /** + * Test for null subscription key + */ + @Test + public void nullSubscriptionKey() { + assertThrows(NullPointerException.class, () -> { + final TextAnalyticsClientBuilder builder = new TextAnalyticsClientBuilder(); + builder.endpoint(getEndpoint()).subscriptionKey(null); + }); + } + + /** + * Test for null AAD credential + */ + @Test + public void nullAADCredential() { + assertThrows(NullPointerException.class, () -> { + final TextAnalyticsClientBuilder builder = new TextAnalyticsClientBuilder(); + builder.endpoint(getEndpoint()).credential(null); + }); + } + + /** + * Test for null service version, which would take take the default service version by default + */ + @Test + public void nullServiceVersion() { + // Arrange + final TextAnalyticsClientBuilder clientBuilder = new TextAnalyticsClientBuilder() + .endpoint(getEndpoint()) + .subscriptionKey(new TextAnalyticsApiKeyCredential(getSubscriptionKey())) + .retryPolicy(new RetryPolicy()) + .httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS)) + .serviceVersion(null); + + if (interceptorManager.isPlaybackMode()) { + clientBuilder.httpClient(interceptorManager.getPlaybackClient()); + } else { + clientBuilder.httpClient(new NettyAsyncHttpClientBuilder().wiretap(true).build()) + .addPolicy(interceptorManager.getRecordPolicy()); + } + + // Action and Assert + validateDetectedLanguages(Arrays.asList(new DetectedLanguage("English", "en", 1.0)), + clientBuilder.buildClient().detectLanguage("This is a test English Text").getDetectedLanguages()); + } + + /** + * Test for default pipeline in client builder + */ + @Test + public void defaultPipeline() { + // Arrange + final TextAnalyticsClientBuilder clientBuilder = new TextAnalyticsClientBuilder() + .endpoint(getEndpoint()) + .subscriptionKey(new TextAnalyticsApiKeyCredential(getSubscriptionKey())) + .configuration(Configuration.getGlobalConfiguration()) + .httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS)); + + if (interceptorManager.isPlaybackMode()) { + clientBuilder.httpClient(interceptorManager.getPlaybackClient()); + } else { + clientBuilder.httpClient(new NettyAsyncHttpClientBuilder().wiretap(true).build()) + .addPolicy(interceptorManager.getRecordPolicy()); + } + + // Action and Assert + validateDetectedLanguages(Arrays.asList(new DetectedLanguage("English", "en", 1.0)), + clientBuilder.buildClient().detectLanguage("This is a test English Text").getDetectedLanguages()); + } } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsClientTestBase.java b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsClientTestBase.java index 914f66f914b3..50864ddaf4f2 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsClientTestBase.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsClientTestBase.java @@ -18,6 +18,7 @@ import com.azure.ai.textanalytics.models.RecognizePiiEntitiesResult; import com.azure.ai.textanalytics.models.TextAnalyticsError; import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.ai.textanalytics.models.TextAnalyticsApiKeyCredential; import com.azure.ai.textanalytics.models.TextDocumentBatchStatistics; import com.azure.ai.textanalytics.models.TextDocumentInput; import com.azure.ai.textanalytics.models.TextDocumentStatistics; @@ -665,4 +666,39 @@ private static void validatePrimaryLanguage(DetectedLanguage expectedLanguage, D assertEquals(expectedLanguage.getName(), actualLanguage.getName()); assertNotNull(actualLanguage.getScore()); } + + private static final String AZURE_TEXT_ANALYTICS_SUBSCRIPTION_KEY = "AZURE_TEXT_ANALYTICS_SUBSCRIPTION_KEY"; + static final String INVALID_KEY = "invalid key"; + + /** + * Create a client builder with endpoint and subscription key credential. + * + * @param endpoint the given endpoint + * @param credential the given {@link TextAnalyticsApiKeyCredential} credential + * @return {@link TextAnalyticsClientBuilder} + */ + TextAnalyticsClientBuilder createClientBuilder(String endpoint, TextAnalyticsApiKeyCredential credential) { + final TextAnalyticsClientBuilder clientBuilder = new TextAnalyticsClientBuilder() + .subscriptionKey(credential) + .endpoint(endpoint); + + if (interceptorManager.isPlaybackMode()) { + clientBuilder.httpClient(interceptorManager.getPlaybackClient()); + } else { + clientBuilder.httpClient(new NettyAsyncHttpClientBuilder().wiretap(true).build()) + .addPolicy(interceptorManager.getRecordPolicy()); + } + + return clientBuilder; + } + + /** + * Get the string of subscription key value based on what running mode is on. + * + * @return the subscription key string + */ + String getSubscriptionKey() { + return interceptorManager.isPlaybackMode() ? "subscriptionKeyInPlayback" + : Configuration.getGlobalConfiguration().get(AZURE_TEXT_ANALYTICS_SUBSCRIPTION_KEY); + } } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/defaultPipeline.json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/defaultPipeline.json new file mode 100644 index 000000000000..63f5409fbd84 --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/defaultPipeline.json @@ -0,0 +1,26 @@ +{ + "networkCallRecords" : [ { + "Method" : "POST", + "Uri" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/text/analytics/v3.0-preview.1/languages", + "Headers" : { + "User-Agent" : "azsdk-java-azure-ai-textanalytics/1.0.0-beta.1 (11.0.4; Windows 10 10.0)", + "x-ms-client-request-id" : "f69a5e04-8452-4625-84ab-39804a550bef", + "Content-Type" : "application/json" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-envoy-upstream-service-time" : "4", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "csp-billing-usage" : "CognitiveServices.TextAnalytics.BatchScoring=1", + "apim-request-id" : "dff46a23-4b2a-4205-85e0-9739501b72ee", + "retry-after" : "0", + "StatusCode" : "200", + "Body" : "{\"documents\":[{\"id\":\"0\",\"detectedLanguages\":[{\"name\":\"English\",\"iso6391Name\":\"en\",\"score\":1.0}]}],\"errors\":[],\"modelVersion\":\"2019-10-01\"}", + "Date" : "Mon, 27 Jan 2020 00:59:47 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/invalidKey.json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/invalidKey.json new file mode 100644 index 000000000000..7ecedab25756 --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/invalidKey.json @@ -0,0 +1,20 @@ +{ + "networkCallRecords" : [ { + "Method" : "POST", + "Uri" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/text/analytics/v3.0-preview.1/languages", + "Headers" : { + "User-Agent" : "azsdk-java-azure-ai-textanalytics/1.0.0-beta.1 (11.0.4; Windows 10 10.0)", + "x-ms-client-request-id" : "2857ac1c-91a4-4494-bb86-7eb0e26d9e1a", + "Content-Type" : "application/json" + }, + "Response" : { + "retry-after" : "0", + "Content-Length" : "224", + "StatusCode" : "401", + "Body" : "{\"error\":{\"code\":\"401\",\"message\":\"Access denied due to invalid subscription key or wrong API endpoint. Make sure to provide a valid key for an active subscription and use a correct regional API endpoint for your resource.\"}}", + "Date" : "Mon, 27 Jan 2020 00:59:47 GMT" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/missingEndpoint.json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/missingEndpoint.json new file mode 100644 index 000000000000..ba5f37f8f855 --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/missingEndpoint.json @@ -0,0 +1,4 @@ +{ + "networkCallRecords" : [ ], + "variables" : [ ] +} \ No newline at end of file diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/nullAADCredential.json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/nullAADCredential.json new file mode 100644 index 000000000000..ba5f37f8f855 --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/nullAADCredential.json @@ -0,0 +1,4 @@ +{ + "networkCallRecords" : [ ], + "variables" : [ ] +} \ No newline at end of file diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/nullServiceVersion.json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/nullServiceVersion.json new file mode 100644 index 000000000000..73587a8e9028 --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/nullServiceVersion.json @@ -0,0 +1,26 @@ +{ + "networkCallRecords" : [ { + "Method" : "POST", + "Uri" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/text/analytics/v3.0-preview.1/languages", + "Headers" : { + "User-Agent" : "azsdk-java-azure-ai-textanalytics/1.0.0-beta.1 (11.0.4; Windows 10 10.0)", + "x-ms-client-request-id" : "17547883-0c92-45dc-9e4c-c5bbd82512c4", + "Content-Type" : "application/json" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-envoy-upstream-service-time" : "12", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "csp-billing-usage" : "CognitiveServices.TextAnalytics.BatchScoring=1", + "apim-request-id" : "04e76a72-266f-4df8-86c0-feb9681a6986", + "retry-after" : "0", + "StatusCode" : "200", + "Body" : "{\"documents\":[{\"id\":\"0\",\"detectedLanguages\":[{\"name\":\"English\",\"iso6391Name\":\"en\",\"score\":1.0}]}],\"errors\":[],\"modelVersion\":\"2019-10-01\"}", + "Date" : "Mon, 27 Jan 2020 00:59:47 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/nullSubscriptionKey.json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/nullSubscriptionKey.json new file mode 100644 index 000000000000..ba5f37f8f855 --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/nullSubscriptionKey.json @@ -0,0 +1,4 @@ +{ + "networkCallRecords" : [ ], + "variables" : [ ] +} \ No newline at end of file diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/updateToInvalidKey.json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/updateToInvalidKey.json new file mode 100644 index 000000000000..f768a8efd741 --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/updateToInvalidKey.json @@ -0,0 +1,20 @@ +{ + "networkCallRecords" : [ { + "Method" : "POST", + "Uri" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/text/analytics/v3.0-preview.1/languages", + "Headers" : { + "User-Agent" : "azsdk-java-azure-ai-textanalytics/1.0.0-beta.1 (11.0.4; Windows 10 10.0)", + "x-ms-client-request-id" : "04c699d4-b729-4fd1-b7af-0463235ccfcb", + "Content-Type" : "application/json" + }, + "Response" : { + "retry-after" : "0", + "Content-Length" : "224", + "StatusCode" : "401", + "Body" : "{\"error\":{\"code\":\"401\",\"message\":\"Access denied due to invalid subscription key or wrong API endpoint. Make sure to provide a valid key for an active subscription and use a correct regional API endpoint for your resource.\"}}", + "Date" : "Mon, 27 Jan 2020 00:59:47 GMT" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/updateToValidKey.json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/updateToValidKey.json new file mode 100644 index 000000000000..0a2bf6142763 --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/updateToValidKey.json @@ -0,0 +1,26 @@ +{ + "networkCallRecords" : [ { + "Method" : "POST", + "Uri" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/text/analytics/v3.0-preview.1/languages", + "Headers" : { + "User-Agent" : "azsdk-java-azure-ai-textanalytics/1.0.0-beta.1 (11.0.4; Windows 10 10.0)", + "x-ms-client-request-id" : "2ec87796-1601-41a0-b817-97d36d52a3ac", + "Content-Type" : "application/json" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-envoy-upstream-service-time" : "4", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "csp-billing-usage" : "CognitiveServices.TextAnalytics.BatchScoring=1", + "apim-request-id" : "3cb40441-eeb2-4af5-884f-39ff4818ac55", + "retry-after" : "0", + "StatusCode" : "200", + "Body" : "{\"documents\":[{\"id\":\"0\",\"detectedLanguages\":[{\"name\":\"English\",\"iso6391Name\":\"en\",\"score\":1.0}]}],\"errors\":[],\"modelVersion\":\"2019-10-01\"}", + "Date" : "Mon, 27 Jan 2020 00:59:47 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/validKey.json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/validKey.json new file mode 100644 index 000000000000..ef0d656497ed --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/validKey.json @@ -0,0 +1,26 @@ +{ + "networkCallRecords" : [ { + "Method" : "POST", + "Uri" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/text/analytics/v3.0-preview.1/languages", + "Headers" : { + "User-Agent" : "azsdk-java-azure-ai-textanalytics/1.0.0-beta.1 (11.0.4; Windows 10 10.0)", + "x-ms-client-request-id" : "0851291e-a96c-43bb-afb3-8138cb103c79", + "Content-Type" : "application/json" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-envoy-upstream-service-time" : "4", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", + "x-content-type-options" : "nosniff", + "csp-billing-usage" : "CognitiveServices.TextAnalytics.BatchScoring=1", + "apim-request-id" : "9a03bffa-a493-4ddc-b098-e85f948dab22", + "retry-after" : "0", + "StatusCode" : "200", + "Body" : "{\"documents\":[{\"id\":\"0\",\"detectedLanguages\":[{\"name\":\"English\",\"iso6391Name\":\"en\",\"score\":1.0}]}],\"errors\":[],\"modelVersion\":\"2019-10-01\"}", + "Date" : "Mon, 27 Jan 2020 01:04:03 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + } ], + "variables" : [ ] +} From 34cbb46575da85cdfa314841f6fac6d201509e60 Mon Sep 17 00:00:00 2001 From: Mitch Denny Date: Wed, 29 Jan 2020 09:17:29 +1100 Subject: [PATCH 8/8] Code coverage in aggregate reports (#7734) * Drop in code coverage generation. * Set pom file location. * Increase job timeout. * Remove nio dependency for now. --- eng/jacoco-test-coverage/pom.xml | 5 ---- eng/pipelines/aggregate-reports.yml | 36 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/eng/jacoco-test-coverage/pom.xml b/eng/jacoco-test-coverage/pom.xml index 17b2d99bfead..61ec331461eb 100644 --- a/eng/jacoco-test-coverage/pom.xml +++ b/eng/jacoco-test-coverage/pom.xml @@ -132,11 +132,6 @@ azure-storage-blob-cryptography 12.4.0-beta.1 - - com.azure - azure-storage-blob-nio - 12.0.0-beta.1 - com.azure azure-storage-file-share diff --git a/eng/pipelines/aggregate-reports.yml b/eng/pipelines/aggregate-reports.yml index eb1b7ed34c67..50db37839d07 100644 --- a/eng/pipelines/aggregate-reports.yml +++ b/eng/pipelines/aggregate-reports.yml @@ -4,6 +4,7 @@ pr: none jobs: - job: Generate + timeoutInMinutes: 180 variables: - template: templates/variables/globals.yml pool: @@ -50,6 +51,41 @@ jobs: publishJUnitResults: false goals: 'install site:site site:stage' + - task: Maven@3 + displayName: 'Generate aggregate code coverage report' + inputs: + mavenPomFile: 'pom.client.xml' + options: '$(DefaultOptions) -Dinclude-non-shipping-modules -Dgpg.skip -Dmaven.javadoc.skip=true -Dcheckstyle.skip=true -Dspotbugs.skip=true' + mavenOptions: '-Xmx3072m $(LoggingOptions)' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.11' + jdkArchitectureOption: 'x64' + publishJUnitResults: false + goals: 'verify' + + - task: PublishTestResults@2 + condition: succeededOrFailed() + inputs: + mergeTestResults: true + testRunTitle: 'Linux on Java 1.11' + + # Azure DevOps only seems to respect the last code coverage result published, so only do this for Linux + Java LTS. + # Code coverage reporting is setup only for Track 2 modules. + - task: PublishCodeCoverageResults@1 + inputs: + codeCoverageTool: JaCoCo + summaryFileLocation: eng/jacoco-test-coverage/target/site/test-coverage/jacoco.xml + reportDirectory: eng/jacoco-test-coverage/target/site/test-coverage/ + failIfCoverageEmpty: true + + # Publish code coverage to an artifact so it can be uploaded to the Maven site. + # Do this for track 2 modules only. Code coverage from previous step is only published for Linux + Java LTS. + - task: PublishPipelineArtifact@0 + displayName: 'Publish coverage artifact' + inputs: + artifactName: coverage + targetPath: eng/jacoco-test-coverage/target/site/ + - script: | git clone https://github.com/JonathanGiles/DependencyChecker.git mkdir input && cp eng/DependencyChecker/client_dependencies.json input/dependencies.json