{
+ /**
+ * Creates a new instance of {@link CbsAuthorizationType} without a {@link #toString()} value.
+ *
+ * This constructor shouldn't be called as it will produce a {@link CbsAuthorizationType} which doesn't have a
+ * String enum value.
+ *
+ * @deprecated Use one of the constants or the {@link #fromString(String, Class)} factory method.
+ */
+ @Deprecated
+ public CbsAuthorizationType() {
+ }
+
/**
* Authorize with CBS through a shared access signature.
*/
@@ -18,7 +30,7 @@ public final class CbsAuthorizationType extends ExpandableStringEnum
* This is used in the case where Azure Active Directory is used for authentication and the authenticated user
* wants to authorize with Azure Event Hubs.
*/
diff --git a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/models/DeliveryState.java b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/models/DeliveryState.java
index 8b2933701eeb..9f7567812b04 100644
--- a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/models/DeliveryState.java
+++ b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/models/DeliveryState.java
@@ -41,6 +41,18 @@ public final class DeliveryState extends ExpandableStringEnum {
*/
public static final DeliveryState TRANSACTIONAL = fromString("TRANSACTIONAL", DeliveryState.class);
+ /**
+ * Creates a new instance of {@link DeliveryState} without a {@link #toString()} value.
+ *
+ * This constructor shouldn't be called as it will produce a {@link DeliveryState} which doesn't have a String
+ * enum value.
+ *
+ * @deprecated Use one of the constants or the {@link #fromString(String, Class)} factory method.
+ */
+ @Deprecated
+ public DeliveryState() {
+ }
+
/**
* Gets the corresponding delivery state from its string representation.
*
diff --git a/sdk/core/azure-core-management/src/main/java/com/azure/core/management/ResourceAuthorIdentityType.java b/sdk/core/azure-core-management/src/main/java/com/azure/core/management/ResourceAuthorIdentityType.java
index 4c1cf695dfc1..73080a73de9e 100644
--- a/sdk/core/azure-core-management/src/main/java/com/azure/core/management/ResourceAuthorIdentityType.java
+++ b/sdk/core/azure-core-management/src/main/java/com/azure/core/management/ResourceAuthorIdentityType.java
@@ -22,6 +22,18 @@ public final class ResourceAuthorIdentityType extends ExpandableStringEnum
+ * This constructor shouldn't be called as it will produce a {@link ResourceAuthorIdentityType} which doesn't have a
+ * String enum value.
+ *
+ * @deprecated Use one of the constants or the {@link #fromString(String, Class)} factory method.
+ */
+ @Deprecated
+ public ResourceAuthorIdentityType() {
+ }
+
/**
* Creates or finds a ResourceAuthorIdentityType from its string representation.
*
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/annotation/BodyParam.java b/sdk/core/azure-core/src/main/java/com/azure/core/annotation/BodyParam.java
index bcdcb534c89e..5cc0bad8f5a4 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/annotation/BodyParam.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/annotation/BodyParam.java
@@ -43,7 +43,9 @@
@Target(PARAMETER)
public @interface BodyParam {
/**
- * @return the Content-Type that the body should be treated as
+ * Gets the Content-Type for the body.
+ *
+ * @return The Content-Type for the body.
*/
String value();
}
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/annotation/FormParam.java b/sdk/core/azure-core/src/main/java/com/azure/core/annotation/FormParam.java
index b4f57b875f9f..b8f12b1b59aa 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/annotation/FormParam.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/annotation/FormParam.java
@@ -29,6 +29,8 @@
@Target(PARAMETER)
public @interface FormParam {
/**
+ * Gets the name of the key in a key-value pair as part of the form data.
+ *
* @return The name of the key in a key value pair as part of the form data.
*/
String value();
@@ -36,7 +38,6 @@
/**
* Whether the form parameter is already form encoded.
*
- *
* A value true for this argument indicates that value of {@link FormParam#value()} is already encoded hence engine
* should not encode it, by default value will be encoded.
*
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/annotation/UnexpectedResponseExceptionTypes.java b/sdk/core/azure-core/src/main/java/com/azure/core/annotation/UnexpectedResponseExceptionTypes.java
index db5d2bc8ef60..bbececfe2577 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/annotation/UnexpectedResponseExceptionTypes.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/annotation/UnexpectedResponseExceptionTypes.java
@@ -18,6 +18,8 @@
@Target(METHOD)
public @interface UnexpectedResponseExceptionTypes {
/**
+ * Gets an array of {@link UnexpectedResponseExceptionType} that annotate a method.
+ *
* @return array of {@link UnexpectedResponseExceptionType} that annotate a method.
*/
UnexpectedResponseExceptionType[] value();
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/credential/AccessToken.java b/sdk/core/azure-core/src/main/java/com/azure/core/credential/AccessToken.java
index b12996a55f37..ab16bc6a0801 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/credential/AccessToken.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/credential/AccessToken.java
@@ -14,6 +14,7 @@ public class AccessToken {
/**
* Creates an access token instance.
+ *
* @param token the token string.
* @param expiresAt the expiration time.
*/
@@ -23,21 +24,27 @@ public AccessToken(String token, OffsetDateTime expiresAt) {
}
/**
- * @return the token string.
+ * Gets the token.
+ *
+ * @return The token.
*/
public String getToken() {
return token;
}
/**
- * @return the time when the token expires, in UTC.
+ * Gets the time when the token expires, in UTC.
+ *
+ * @return The time when the token expires, in UTC.
*/
public OffsetDateTime getExpiresAt() {
return expiresAt;
}
/**
- * @return if the token has expired.
+ * Whether the token has expired.
+ *
+ * @return Whether the token has expired.
*/
public boolean isExpired() {
return OffsetDateTime.now().isAfter(expiresAt);
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/exception/HttpRequestException.java b/sdk/core/azure-core/src/main/java/com/azure/core/exception/HttpRequestException.java
index 6ff7064a3d8e..d30e8c99a3fc 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/exception/HttpRequestException.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/exception/HttpRequestException.java
@@ -77,6 +77,8 @@ public HttpRequestException(final String message, final HttpRequest request, fin
}
/**
+ * Gets the {@link HttpRequest} being sent when the exception occurred.
+ *
* @return The {@link HttpRequest} being sent when the exception occurred.
*/
public HttpRequest getRequest() {
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/exception/HttpResponseException.java b/sdk/core/azure-core/src/main/java/com/azure/core/exception/HttpResponseException.java
index 223d0e4d04a9..d042c7090e3a 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/exception/HttpResponseException.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/exception/HttpResponseException.java
@@ -99,6 +99,8 @@ public HttpResponseException(final String message, final HttpResponse response,
}
/**
+ * Gets the {@link HttpResponse} received that is associated to the exception.
+ *
* @return The {@link HttpResponse} received that is associated to the exception.
*/
public HttpResponse getResponse() {
@@ -106,6 +108,8 @@ public HttpResponse getResponse() {
}
/**
+ * Gets the deserialized HTTP response value.
+ *
* @return The deserialized HTTP response value.
*/
public Object getValue() {
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/http/HttpAuthorization.java b/sdk/core/azure-core/src/main/java/com/azure/core/http/HttpAuthorization.java
index 9e76924b2a18..306aa599e3d4 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/http/HttpAuthorization.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/http/HttpAuthorization.java
@@ -42,6 +42,8 @@ public HttpAuthorization(String scheme, String parameter) {
}
/**
+ * Gets the scheme of the authorization header.
+ *
* @return Scheme of the authorization header.
*/
public String getScheme() {
@@ -49,6 +51,8 @@ public String getScheme() {
}
/**
+ * Gets the credential of the authorization header.
+ *
* @return Credential of the authorization header.
*/
public String getParameter() {
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/http/MatchConditions.java b/sdk/core/azure-core/src/main/java/com/azure/core/http/MatchConditions.java
index 442cb2a53cca..ed79be868319 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/http/MatchConditions.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/http/MatchConditions.java
@@ -13,6 +13,12 @@ public class MatchConditions {
private String ifMatch;
private String ifNoneMatch;
+ /**
+ * Creates a new instance of {@link MatchConditions}.
+ */
+ public MatchConditions() {
+ }
+
/**
* Gets the ETag that resources must match.
*
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/http/ProxyOptions.java b/sdk/core/azure-core/src/main/java/com/azure/core/http/ProxyOptions.java
index 3121bb5742b1..40bb16682954 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/http/ProxyOptions.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/http/ProxyOptions.java
@@ -127,6 +127,8 @@ public ProxyOptions setNonProxyHosts(String nonProxyHosts) {
}
/**
+ * Gets the address of the proxy.
+ *
* @return the address of the proxy.
*/
public InetSocketAddress getAddress() {
@@ -134,6 +136,8 @@ public InetSocketAddress getAddress() {
}
/**
+ * Gets the type of the prxoy.
+ *
* @return the type of the proxy.
*/
public Type getType() {
@@ -141,13 +145,17 @@ public Type getType() {
}
/**
- * @return the proxy user name.
+ * Gets the proxy username.
+ *
+ * @return the proxy username.
*/
public String getUsername() {
return this.username;
}
/**
+ * Gets the proxy password.
+ *
* @return the proxy password.
*/
public String getPassword() {
@@ -155,6 +163,8 @@ public String getPassword() {
}
/**
+ * Gets the host that bypass the proxy.
+ *
* @return the hosts that bypass the proxy.
*/
public String getNonProxyHosts() {
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/http/RequestConditions.java b/sdk/core/azure-core/src/main/java/com/azure/core/http/RequestConditions.java
index 392813a8d3b5..f8e3430b7aad 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/http/RequestConditions.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/http/RequestConditions.java
@@ -15,6 +15,12 @@ public class RequestConditions extends MatchConditions {
private OffsetDateTime ifModifiedSince;
private OffsetDateTime ifUnmodifiedSince;
+ /**
+ * Creates a new instance of {@link RequestConditions}.
+ */
+ public RequestConditions() {
+ }
+
/**
* Optionally limit requests to resources that match the passed ETag.
*
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/AddDatePolicy.java b/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/AddDatePolicy.java
index a3184967ed2a..9b6f2ddb39d9 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/AddDatePolicy.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/AddDatePolicy.java
@@ -39,6 +39,12 @@ protected void beforeSendingRequest(HttpPipelineCallContext context) {
}
};
+ /**
+ * Creates a new instance of {@link AddDatePolicy}.
+ */
+ public AddDatePolicy() {
+ }
+
@Override
public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
return INNER.process(context, next);
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/AddHeadersFromContextPolicy.java b/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/AddHeadersFromContextPolicy.java
index 716118f6123c..c3b174ac04c1 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/AddHeadersFromContextPolicy.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/AddHeadersFromContextPolicy.java
@@ -60,6 +60,12 @@ protected void beforeSendingRequest(HttpPipelineCallContext context) {
}
};
+ /**
+ * Creates a new instance of {@link AddHeadersFromContextPolicy}.
+ */
+ public AddHeadersFromContextPolicy() {
+ }
+
@Override
public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
return INNER.process(context, next);
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/CookiePolicy.java b/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/CookiePolicy.java
index 502fcb165882..2164f7fc5f21 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/CookiePolicy.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/CookiePolicy.java
@@ -66,6 +66,12 @@ protected HttpResponse afterReceivedResponse(HttpPipelineCallContext context, Ht
}
};
+ /**
+ * Creates a new instance of {@link CookiePolicy}.
+ */
+ public CookiePolicy() {
+ }
+
@Override
public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
return inner.process(context, next);
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/ExponentialBackoffOptions.java b/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/ExponentialBackoffOptions.java
index c19f184c8b77..d7affaf5a168 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/ExponentialBackoffOptions.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/ExponentialBackoffOptions.java
@@ -19,6 +19,12 @@ public class ExponentialBackoffOptions {
private Duration baseDelay;
private Duration maxDelay;
+ /**
+ * Creates a new instance of {@link ExponentialBackoffOptions}.
+ */
+ public ExponentialBackoffOptions() {
+ }
+
/**
* Gets the max retry attempts that can be made.
*
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/HttpLogDetailLevel.java b/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/HttpLogDetailLevel.java
index ca21730a8869..7bbfbc3d2b80 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/HttpLogDetailLevel.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/HttpLogDetailLevel.java
@@ -67,21 +67,27 @@ static HttpLogDetailLevel fromConfiguration(Configuration configuration) {
}
/**
- * @return a value indicating whether a request's URL should be logged.
+ * Whether a URL should be logged.
+ *
+ * @return Whether a URL should be logged.
*/
public boolean shouldLogUrl() {
return this != NONE;
}
/**
- * @return a value indicating whether HTTP message headers should be logged.
+ * Whether headers should be logged.
+ *
+ * @return Whether headers should be logged.
*/
public boolean shouldLogHeaders() {
return this == HEADERS || this == BODY_AND_HEADERS;
}
/**
- * @return a value indicating whether HTTP message bodies should be logged.
+ * Whether a body should be logged.
+ *
+ * @return Whether a body should be logged.
*/
public boolean shouldLogBody() {
return this == BODY || this == BODY_AND_HEADERS;
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/HttpPipelineSyncPolicy.java b/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/HttpPipelineSyncPolicy.java
index 0f43b5aa032f..00875ee0938c 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/HttpPipelineSyncPolicy.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/HttpPipelineSyncPolicy.java
@@ -13,6 +13,11 @@
* Represents a {@link HttpPipelinePolicy} that doesn't do any asynchronous or synchronously blocking operations.
*/
public class HttpPipelineSyncPolicy implements HttpPipelinePolicy {
+ /**
+ * Creates a new instance of {@link HttpPipelineSyncPolicy}.
+ */
+ public HttpPipelineSyncPolicy() {
+ }
/**
* {@inheritDoc}
@@ -40,6 +45,7 @@ public final HttpResponse processSync(HttpPipelineCallContext context, HttpPipel
/**
* Method is invoked before the request is sent.
+ *
* @param context The request context.
*/
protected void beforeSendingRequest(HttpPipelineCallContext context) {
@@ -48,6 +54,7 @@ protected void beforeSendingRequest(HttpPipelineCallContext context) {
/**
* Method is invoked after the response is received.
+ *
* @param context The request context.
* @param response The response received.
* @return The transformed response.
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/http/rest/RequestOptions.java b/sdk/core/azure-core/src/main/java/com/azure/core/http/rest/RequestOptions.java
index 5a1dec2cfe2a..5486361e80b1 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/http/rest/RequestOptions.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/http/rest/RequestOptions.java
@@ -125,6 +125,12 @@ public final class RequestOptions {
private EnumSet errorOptions = DEFAULT;
private Context context;
+ /**
+ * Creates a new instance of {@link RequestOptions}.
+ */
+ public RequestOptions() {
+ }
+
/**
* Gets the request callback, applying all the configurations set on this RequestOptions.
*
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/models/CloudEventDataFormat.java b/sdk/core/azure-core/src/main/java/com/azure/core/models/CloudEventDataFormat.java
index a2e64e5075d3..2a9c765eb202 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/models/CloudEventDataFormat.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/models/CloudEventDataFormat.java
@@ -5,6 +5,7 @@
import com.azure.core.util.BinaryData;
import com.azure.core.util.ExpandableStringEnum;
+import com.fasterxml.jackson.annotation.JsonCreator;
/**
* Representation of the data format for a {@link CloudEvent}.
@@ -15,6 +16,18 @@
* @see CloudEvent#CloudEvent(String, String, BinaryData, com.azure.core.models.CloudEventDataFormat, String)
*/
public final class CloudEventDataFormat extends ExpandableStringEnum {
+ /**
+ * Creates a new instance of {@link CloudEventDataFormat} without a {@link #toString()} value.
+ *
+ * This constructor shouldn't be called as it will produce a {@link CloudEventDataFormat} which doesn't
+ * have a String enum value.
+ *
+ * @deprecated Use one of the constants or the {@link #fromString(String)} factory method.
+ */
+ @Deprecated
+ public CloudEventDataFormat() {
+ }
+
/**
* Bytes format.
*/
@@ -24,4 +37,15 @@ public final class CloudEventDataFormat extends ExpandableStringEnum {
+ /**
+ * Creates a new instance of {@link GeoObjectType} without a {@link #toString()} value.
+ *
+ * This constructor shouldn't be called as it will produce a {@link GeoObjectType} which doesn't
+ * have a String enum value.
+ *
+ * @deprecated Use one of the constants or the {@link #fromString(String)} factory method.
+ */
+ @Deprecated
+ public GeoObjectType() {
+ }
+
/**
* GeoJSON point.
*/
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/models/MessageContent.java b/sdk/core/azure-core/src/main/java/com/azure/core/models/MessageContent.java
index 5f0093dd225d..3bd2206ab88f 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/models/MessageContent.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/models/MessageContent.java
@@ -14,6 +14,12 @@ public class MessageContent {
private BinaryData binaryData;
private String contentType;
+ /**
+ * Creates a new instance of {@link MessageContent}.
+ */
+ public MessageContent() {
+ }
+
/**
* Gets the message body.
*
@@ -27,7 +33,6 @@ public BinaryData getBodyAsBinaryData() {
* Sets the message body.
*
* @param binaryData The message body.
- *
* @return The updated {@link MessageContent} object.
*/
public MessageContent setBodyAsBinaryData(BinaryData binaryData) {
@@ -48,7 +53,6 @@ public String getContentType() {
* Sets the content type.
*
* @param contentType The content type.
- *
* @return The updated {@link MessageContent} object.
*/
public MessageContent setContentType(String contentType) {
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/ClientOptions.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/ClientOptions.java
index c824701878c7..2c468dab74ae 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/util/ClientOptions.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/ClientOptions.java
@@ -27,6 +27,12 @@ public class ClientOptions {
private MetricsOptions metricsOptions;
+ /**
+ * Creates a new instance of {@link ClientOptions}.
+ */
+ public ClientOptions() {
+ }
+
/**
* Gets the application ID.
*
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/ExpandableStringEnum.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/ExpandableStringEnum.java
index 3b9b2b1ad165..b70d5b352e39 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/util/ExpandableStringEnum.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/ExpandableStringEnum.java
@@ -23,6 +23,18 @@ public abstract class ExpandableStringEnum> {
private String name;
private Class clazz;
+ /**
+ * Creates a new instance of {@link ExpandableStringEnum} without a {@link #toString()} value.
+ *
+ * This constructor shouldn't be called as it will produce a {@link ExpandableStringEnum} which doesn't
+ * have a String enum value.
+ *
+ * @deprecated Use the {@link #fromString(String, Class)} factory method.
+ */
+ @Deprecated
+ public ExpandableStringEnum() {
+ }
+
/**
* Creates an instance of the specific expandable string enum from a String.
*
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/HttpClientOptions.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/HttpClientOptions.java
index 415f599157c3..6fb1942c1401 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/util/HttpClientOptions.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/HttpClientOptions.java
@@ -57,6 +57,12 @@ public final class HttpClientOptions extends ClientOptions {
private Duration connectionIdleTimeout;
private Class extends HttpClientProvider> httpClientProvider;
+ /**
+ * Creates a new instance of {@link HttpClientOptions}.
+ */
+ public HttpClientOptions() {
+ }
+
@Override
public HttpClientOptions setApplicationId(String applicationId) {
super.setApplicationId(applicationId);
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/polling/AsyncPollResponse.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/polling/AsyncPollResponse.java
index 9ae1d1c6437b..a8c471606dc7 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/util/polling/AsyncPollResponse.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/polling/AsyncPollResponse.java
@@ -54,6 +54,7 @@ public final class AsyncPollResponse {
/**
* Represents the status of the long-running operation at the time the last polling operation finished successfully.
+ *
* @return A {@link LongRunningOperationStatus} representing the result of the poll operation.
*/
public LongRunningOperationStatus getStatus() {
@@ -71,7 +72,10 @@ public T getValue() {
}
/**
- * @return a Mono, upon subscription it cancels the remote long-running operation if cancellation
+ * Gets a {@link Mono} whereupon subscription it cancels the remote long-running operation if cancellation is
+ * supported by the service.
+ *
+ * @return A {@link Mono} whereupon subscription it cancels the remote long-running operation if cancellation
* is supported by the service.
*/
public Mono cancelOperation() {
@@ -86,9 +90,14 @@ public Mono cancelOperation() {
}
/**
- * @return a Mono, upon subscription it fetches the final result of long-running operation if it
- * is supported by the service. If the long-running operation is not completed, then an empty
- * Mono will be returned.
+ * Gets a {@link Mono} whereupon subscription it fetches the final result of the long-running operation if it is
+ * supported by the service.
+ *
+ * If the long-running operation isn't complete an empty {@link Mono} will be returned.
+ *
+ * @return A {@link Mono} whereupon subscription it fetches the final result of the long-running operation if it is
+ * supported by the service. If the long-running operation is not completed, then an empty {@link Mono} will be
+ * returned.
*/
public Mono getFinalResult() {
return Mono.defer(() -> {
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/polling/LongRunningOperationStatus.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/polling/LongRunningOperationStatus.java
index 1e63ba9c5750..3246b671ed8b 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/util/polling/LongRunningOperationStatus.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/polling/LongRunningOperationStatus.java
@@ -18,6 +18,18 @@ public final class LongRunningOperationStatus extends ExpandableStringEnum
+ * This constructor shouldn't be called as it will produce a {@link LongRunningOperationStatus} which doesn't
+ * have a String enum value.
+ *
+ * @deprecated Use one of the constants or the {@link #fromString(String, boolean)} factory method.
+ */
+ @Deprecated
+ public LongRunningOperationStatus() {
+ }
+
/** Represents that polling has not yet started for this long-running operation. */
public static final LongRunningOperationStatus NOT_STARTED = fromString("NOT_STARTED", false);
@@ -41,7 +53,7 @@ public final class LongRunningOperationStatus extends ExpandableStringEnum operationStatusMap;
+ private static final Map OPERATION_STATUS_MAP;
static {
Map opStatusMap = new HashMap<>();
opStatusMap.put(NOT_STARTED.toString(), NOT_STARTED);
@@ -49,7 +61,7 @@ public final class LongRunningOperationStatus extends ExpandableStringEnum> actual) {
}
/**
+ * Gets a synchronous blocking poller.
+ *
* @return a synchronous blocking poller.
*/
public SyncPoller getSyncPoller() {
@@ -521,11 +523,11 @@ private Duration getDelay(PollResponse pollResponse) {
/**
* A utility to get One-Time-Executable-Mono that execute an activation function at most once.
- *
+ *
* When subscribed to such a Mono it internally subscribes to a Mono that perform an activation
* function. The One-Time-Executable-Mono caches the result of activation function as a PollResponse
* in {@code rootContext}, this cached response will be used by any future subscriptions.
- *
+ *
* Note: The standard cache() operator can't be used to achieve one time execution, because it caches
* error terminal signal and forward it to any future subscriptions. If there is an error while executing
* activation function then error should not be cached but it should be forward it to subscription that
@@ -533,7 +535,7 @@ private Duration getDelay(PollResponse pollResponse) {
* instead activation function should again invoked. Once a subscription result in successful execution
* of activation function then it will be cached in {@code rootContext} and will be used by any future
* subscriptions.
- *
+ *
* The One-Time-Executable-Mono handles concurrent calls to activation. Only one of them will be able
* to execute the activation function and other subscriptions will keep resubscribing until it sees
* a activation happened or get a chance to call activation as the one previously entered the critical
diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/polling/PollingContext.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/polling/PollingContext.java
index 6cd090f1fa64..f282f141b4d8 100644
--- a/sdk/core/azure-core/src/main/java/com/azure/core/util/polling/PollingContext.java
+++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/polling/PollingContext.java
@@ -46,14 +46,18 @@ public PollingContext setData(String name, String value) {
}
/**
- * @return the activation {@link PollResponse} holding result of activation operation call.
+ * Gets the activation {@link PollResponse} holding the result of an activation operation call.
+ *
+ * @return The activation {@link PollResponse} holding the result of an activation operation call.
*/
public PollResponse getActivationResponse() {
return this.activationResponse;
}
/**
- * @return the latest {@link PollResponse} from pollOperation.
+ * Gets the latest {@link PollResponse} in the polling operation.
+ *
+ * @return The latest {@link PollResponse} in the polling operation.
*/
public PollResponse getLatestResponse() {
return this.latestResponse;
@@ -62,20 +66,15 @@ public PollResponse getLatestResponse() {
/**
* Sets latest {@link PollResponse} from pollOperation.
*
- * PACKAGE INTERNAL METHOD
- *
* @param latestResponse the poll response
*/
void setLatestResponse(PollResponse latestResponse) {
- this.latestResponse = Objects.requireNonNull(latestResponse,
- "'latestResponse' is required.");
+ this.latestResponse = Objects.requireNonNull(latestResponse, "'latestResponse' is required.");
}
/**
* Sets activation {@link PollResponse} holding result of activation operation call.
*
- * PACKAGE INTERNAL METHOD
- *
* @param activationResponse the activation response
*/
void setOnetimeActivationResponse(PollResponse activationResponse) {
@@ -89,15 +88,11 @@ void setOnetimeActivationResponse(PollResponse activationResponse) {
}
PollingContext copy() {
- return new PollingContext<>(this.activationResponse,
- this.latestResponse,
- new HashMap<>(this.map));
+ return new PollingContext<>(this.activationResponse, this.latestResponse, new HashMap<>(this.map));
}
/**
* Creates PollingContext.
- *
- * Package internal default constructor.
*/
PollingContext() {
this.map = new HashMap<>();
@@ -110,14 +105,10 @@ PollingContext copy() {
* @param latestResponse latest poll response from pollOperation.
* @param map the map to store context
*/
- private PollingContext(PollResponse activationResponse,
- PollResponse latestResponse,
- Map map) {
- this.activationResponse = Objects.requireNonNull(activationResponse,
- "'activationResponse' cannot be null.");
- this.latestResponse = Objects.requireNonNull(latestResponse,
- "'latestResponse' cannot be null.");
- this.map = Objects.requireNonNull(map,
- "'map' cannot be null.");
+ private PollingContext(PollResponse activationResponse, PollResponse latestResponse,
+ Map map) {
+ this.activationResponse = Objects.requireNonNull(activationResponse, "'activationResponse' cannot be null.");
+ this.latestResponse = Objects.requireNonNull(latestResponse, "'latestResponse' cannot be null.");
+ this.map = Objects.requireNonNull(map, "'map' cannot be null.");
}
}
diff --git a/sdk/core/azure-core/src/samples/java/com/azure/core/util/ConfigurationJavaDocCodeSnippet.java b/sdk/core/azure-core/src/samples/java/com/azure/core/util/ConfigurationJavaDocCodeSnippet.java
index 105bb9625d69..cd0139c1940a 100644
--- a/sdk/core/azure-core/src/samples/java/com/azure/core/util/ConfigurationJavaDocCodeSnippet.java
+++ b/sdk/core/azure-core/src/samples/java/com/azure/core/util/ConfigurationJavaDocCodeSnippet.java
@@ -153,6 +153,10 @@ public static final class SampleEnumProperty extends ExpandableStringEnum validateEqualsSupplier() {
}
public static final class TestStringEnum extends ExpandableStringEnum {
+ @Deprecated
+ public TestStringEnum() {
+ }
+
static TestStringEnum fromString(String name) {
return fromString(name, TestStringEnum.class);
}
}
public static final class TestStringEnum2 extends ExpandableStringEnum {
+ @Deprecated
+ public TestStringEnum2() {
+ }
+
static TestStringEnum2 fromString(String name) {
return fromString(name, TestStringEnum2.class);
}
}
private static final class PrivateStringEnum extends ExpandableStringEnum {
+ @Deprecated
+ private PrivateStringEnum() {
+ }
+
static PrivateStringEnum fromString(String name) {
return fromString(name, PrivateStringEnum.class);
}
}
public static final class ValuesTestStringEnum extends ExpandableStringEnum {
+ @Deprecated
+ public ValuesTestStringEnum() {
+ }
+
static ValuesTestStringEnum fromString(String name) {
return fromString(name, ValuesTestStringEnum.class);
}
diff --git a/sdk/core/azure-core/src/test/java/com/azure/core/util/serializer/JacksonAdapterSecurityTests.java b/sdk/core/azure-core/src/test/java/com/azure/core/util/serializer/JacksonAdapterSecurityIT.java
similarity index 89%
rename from sdk/core/azure-core/src/test/java/com/azure/core/util/serializer/JacksonAdapterSecurityTests.java
rename to sdk/core/azure-core/src/test/java/com/azure/core/util/serializer/JacksonAdapterSecurityIT.java
index cc5629f2ce7f..3b164a0f77fb 100644
--- a/sdk/core/azure-core/src/test/java/com/azure/core/util/serializer/JacksonAdapterSecurityTests.java
+++ b/sdk/core/azure-core/src/test/java/com/azure/core/util/serializer/JacksonAdapterSecurityIT.java
@@ -13,7 +13,6 @@
import org.junit.jupiter.api.parallel.Isolated;
import java.net.URISyntaxException;
-import java.security.Policy;
import java.security.URIParameter;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
@@ -26,18 +25,18 @@
@SuppressWarnings("removal")
@Execution(ExecutionMode.SAME_THREAD)
@Isolated("Mutates the global SecurityManager")
-public class JacksonAdapterSecurityTests {
+public class JacksonAdapterSecurityIT {
private static final String A_PROPERTY_JSON = "{\"aProperty\":\"aValue\"}";
private static final SimplePojo EXPECTED_SIMPLE_POJO = new SimplePojo("aValue");
private boolean originalUseAccessHelper;
private SecurityManager originalManager;
- private Policy originalPolicy;
+ private java.security.Policy originalPolicy;
public void captureDefaultConfigurations() {
originalUseAccessHelper = JacksonAdapter.isUseAccessHelper();
originalManager = System.getSecurityManager();
- originalPolicy = Policy.getPolicy();
+ originalPolicy = java.security.Policy.getPolicy();
// Set the System property codebase.azure-core to the location of JacksonAdapter's codebase.
// This gets picked up by the policy setting to prevent needing to hardcode the code base location.
@@ -56,7 +55,7 @@ public void captureDefaultConfigurations() {
public void revertDefaultConfigurations() throws NoSuchMethodException, NoSuchFieldException {
JacksonAdapter.setUseAccessHelper(originalUseAccessHelper);
System.setSecurityManager(originalManager);
- Policy.setPolicy(originalPolicy);
+ java.security.Policy.setPolicy(originalPolicy);
// Now that the properties have been used, clear them.
System.clearProperty("codebase.azure-core");
@@ -81,7 +80,8 @@ public void securityPreventsSerialization() throws Exception {
try {
JacksonAdapter adapter = new JacksonAdapter();
- Policy.setPolicy(Policy.getInstance("JavaPolicy", getUriParameter("basic-permissions.policy")));
+ java.security.Policy.setPolicy(java.security.Policy
+ .getInstance("JavaPolicy", getUriParameter("basic-permissions.policy")));
System.setSecurityManager(new SecurityManager());
assertThrows(InvalidDefinitionException.class, () ->
@@ -102,7 +102,8 @@ public void securityAndAccessHelperNotMatchingPreventsSerialization() throws Exc
JacksonAdapter adapter = new JacksonAdapter();
JacksonAdapter.setUseAccessHelper(true);
- Policy.setPolicy(Policy.getInstance("JavaPolicy", getUriParameter("basic-permissions.policy")));
+ java.security.Policy.setPolicy(java.security.Policy
+ .getInstance("JavaPolicy", getUriParameter("basic-permissions.policy")));
System.setSecurityManager(new SecurityManager());
assertThrows(InvalidDefinitionException.class, () ->
@@ -123,7 +124,8 @@ public void securityAndAccessHelperWorks() throws Exception {
JacksonAdapter adapter = new JacksonAdapter();
JacksonAdapter.setUseAccessHelper(true);
- Policy.setPolicy(Policy.getInstance("JavaPolicy", getUriParameter("access-helper-succeeds.policy")));
+ java.security.Policy.setPolicy(java.security.Policy
+ .getInstance("JavaPolicy", getUriParameter("access-helper-succeeds.policy")));
System.setSecurityManager(new SecurityManager());
SimplePojo actual = assertDoesNotThrow(() ->
@@ -154,7 +156,7 @@ public void noSecurityRestrictionsWorks() throws Exception {
}
private static URIParameter getUriParameter(String policyFile) throws URISyntaxException {
- return new URIParameter(JacksonAdapterSecurityTests.class
+ return new URIParameter(JacksonAdapterSecurityIT.class
.getResource("/JacksonAdapterSecurityPolicies/" + policyFile)
.toURI());
}
diff --git a/sdk/parents/azure-client-sdk-parent/pom.xml b/sdk/parents/azure-client-sdk-parent/pom.xml
index 92f21e8086f5..70b79c7952b0 100644
--- a/sdk/parents/azure-client-sdk-parent/pom.xml
+++ b/sdk/parents/azure-client-sdk-parent/pom.xml
@@ -214,6 +214,9 @@
-
+
+
+
@@ -633,6 +636,12 @@
spotbugs
4.2.2
+
+
+ org.ow2.asm
+ asm
+ 9.3
+
${spotbugs.skip}
@@ -645,6 +654,9 @@
${spotbugs.failOnError}
${spotbugs.includeTests}
+
+ ${java.security.manager.configuration}
+
@@ -1148,6 +1160,7 @@
--add-opens java.base/java.lang.invoke=com.azure.core
${additionalFailsafeArgLine}
+ ${java.security.manager.configuration}
@@ -1590,5 +1603,16 @@
+
+
+ java-18-plus-allow-securitymanager
+
+ [18,)
+
+
+
+ -Djava.security.manager=allow
+
+
From 2bb61cb273cc057a34c91b3cbe33b971f2a3fde5 Mon Sep 17 00:00:00 2001
From: Kishore Rajasekar <86338791+ki1729@users.noreply.github.com>
Date: Mon, 31 Oct 2022 08:38:46 -0700
Subject: [PATCH 17/46] Fixed servicebus default proxy configuration bug
(#31832)
* Fixing servicebus default proxy configuration bug
* Updating changelog and tests
---
.../azure-messaging-servicebus/CHANGELOG.md | 2 +-
.../servicebus/ServiceBusClientBuilder.java | 47 +------------------
.../ServiceBusClientBuilderTest.java | 44 ++++++++---------
3 files changed, 21 insertions(+), 72 deletions(-)
diff --git a/sdk/servicebus/azure-messaging-servicebus/CHANGELOG.md b/sdk/servicebus/azure-messaging-servicebus/CHANGELOG.md
index c9aa709ecad8..e22ea796545c 100644
--- a/sdk/servicebus/azure-messaging-servicebus/CHANGELOG.md
+++ b/sdk/servicebus/azure-messaging-servicebus/CHANGELOG.md
@@ -8,7 +8,7 @@
### Breaking Changes
### Bugs Fixed
-- Fixed `listQueues`, `listTopics`, `listRules`, `listSubscriptions`, `createQueue` and `createSubscriptionWithResponse` in `ServiceBusAdministrationClient` class. ([#31712](https://github.com/Azure/azure-sdk-for-java/issues/31712))
+- Fixed incorrect proxy configuration using environment variables. ([24230](https://github.com/Azure/azure-sdk-for-java/issues/24230))
### Other Changes
## 7.12.1 (2022-10-25)
diff --git a/sdk/servicebus/azure-messaging-servicebus/src/main/java/com/azure/messaging/servicebus/ServiceBusClientBuilder.java b/sdk/servicebus/azure-messaging-servicebus/src/main/java/com/azure/messaging/servicebus/ServiceBusClientBuilder.java
index 4a7982f55c0c..35ee837a92f7 100644
--- a/sdk/servicebus/azure-messaging-servicebus/src/main/java/com/azure/messaging/servicebus/ServiceBusClientBuilder.java
+++ b/sdk/servicebus/azure-messaging-servicebus/src/main/java/com/azure/messaging/servicebus/ServiceBusClientBuilder.java
@@ -6,7 +6,6 @@
import com.azure.core.amqp.AmqpClientOptions;
import com.azure.core.amqp.AmqpRetryOptions;
import com.azure.core.amqp.AmqpTransportType;
-import com.azure.core.amqp.ProxyAuthenticationType;
import com.azure.core.amqp.ProxyOptions;
import com.azure.core.amqp.client.traits.AmqpTrait;
import com.azure.core.amqp.implementation.AzureTokenManagerProvider;
@@ -53,9 +52,7 @@
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
-import java.net.InetSocketAddress;
import java.net.MalformedURLException;
-import java.net.Proxy;
import java.net.URL;
import java.time.Duration;
import java.util.Locale;
@@ -745,7 +742,7 @@ private ConnectionOptions getConnectionOptions() {
}
if (proxyOptions == null) {
- proxyOptions = getDefaultProxyConfiguration(configuration);
+ proxyOptions = ProxyOptions.fromConfiguration(configuration);
}
final CbsAuthorizationType authorizationType = credentials instanceof ServiceBusSharedKeyCredential
@@ -770,48 +767,6 @@ private ConnectionOptions getConnectionOptions() {
}
}
- private ProxyOptions getDefaultProxyConfiguration(Configuration configuration) {
- ProxyAuthenticationType authentication = ProxyAuthenticationType.NONE;
- if (proxyOptions != null) {
- authentication = proxyOptions.getAuthentication();
- }
-
- String proxyAddress = configuration.get(Configuration.PROPERTY_HTTP_PROXY);
-
- if (CoreUtils.isNullOrEmpty(proxyAddress)) {
- return ProxyOptions.SYSTEM_DEFAULTS;
- }
-
- return getProxyOptions(authentication, proxyAddress, configuration,
- Boolean.parseBoolean(configuration.get("java.net.useSystemProxies")));
- }
-
- private ProxyOptions getProxyOptions(ProxyAuthenticationType authentication, String proxyAddress,
- Configuration configuration, boolean useSystemProxies) {
- String host;
- int port;
- if (HOST_PORT_PATTERN.matcher(proxyAddress.trim()).find()) {
- final String[] hostPort = proxyAddress.split(":");
- host = hostPort[0];
- port = Integer.parseInt(hostPort[1]);
- final Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
- final String username = configuration.get(ProxyOptions.PROXY_USERNAME);
- final String password = configuration.get(ProxyOptions.PROXY_PASSWORD);
- return new ProxyOptions(authentication, proxy, username, password);
- } else if (useSystemProxies) {
- // java.net.useSystemProxies needs to be set to true in this scenario.
- // If it is set to false 'ProxyOptions' in azure-core will return null.
- com.azure.core.http.ProxyOptions coreProxyOptions = com.azure.core.http.ProxyOptions
- .fromConfiguration(configuration);
- return new ProxyOptions(authentication, new Proxy(coreProxyOptions.getType().toProxyType(),
- coreProxyOptions.getAddress()), coreProxyOptions.getUsername(), coreProxyOptions.getPassword());
- } else {
- LOGGER.verbose("'HTTP_PROXY' was configured but ignored as 'java.net.useSystemProxies' wasn't "
- + "set or was false.");
- return ProxyOptions.SYSTEM_DEFAULTS;
- }
- }
-
private static boolean isNullOrEmpty(String item) {
return item == null || item.isEmpty();
}
diff --git a/sdk/servicebus/azure-messaging-servicebus/src/test/java/com/azure/messaging/servicebus/ServiceBusClientBuilderTest.java b/sdk/servicebus/azure-messaging-servicebus/src/test/java/com/azure/messaging/servicebus/ServiceBusClientBuilderTest.java
index 0c0b084a08a4..260fcf8994ba 100644
--- a/sdk/servicebus/azure-messaging-servicebus/src/test/java/com/azure/messaging/servicebus/ServiceBusClientBuilderTest.java
+++ b/sdk/servicebus/azure-messaging-servicebus/src/test/java/com/azure/messaging/servicebus/ServiceBusClientBuilderTest.java
@@ -234,26 +234,20 @@ void invalidPrefetch() {
@MethodSource("getProxyConfigurations")
@ParameterizedTest
- public void testProxyOptionsConfiguration(String proxyConfiguration, boolean expectedClientCreation) {
+ public void testProxyOptionsConfiguration(String proxyConfiguration) {
Configuration configuration = TestUtils.getGlobalConfiguration().clone();
configuration
.put(Configuration.PROPERTY_HTTP_PROXY, proxyConfiguration)
.put(JAVA_NET_USER_SYSTEM_PROXIES, "true");
- boolean clientCreated = false;
- try {
- ServiceBusReceiverClient syncClient = new ServiceBusClientBuilder()
- .connectionString(NAMESPACE_CONNECTION_STRING)
- .configuration(configuration)
- .receiver()
- .topicName("baz").subscriptionName("bar")
- .receiveMode(ServiceBusReceiveMode.PEEK_LOCK)
- .buildClient();
-
- clientCreated = true;
- } catch (Exception ex) {
- }
- Assertions.assertEquals(expectedClientCreation, clientCreated);
+ // Client creation should not fail with incorrect proxy configuration
+ ServiceBusReceiverClient syncClient = new ServiceBusClientBuilder()
+ .connectionString(NAMESPACE_CONNECTION_STRING)
+ .configuration(configuration)
+ .receiver()
+ .topicName("baz").subscriptionName("bar")
+ .receiveMode(ServiceBusReceiveMode.PEEK_LOCK)
+ .buildClient();
}
@Test
@@ -386,16 +380,16 @@ public void testConnectionWithAzureSasCredential() {
private static Stream getProxyConfigurations() {
return Stream.of(
- Arguments.of("http://localhost:8080", true),
- Arguments.of("localhost:8080", true),
- Arguments.of("localhost_8080", false),
- Arguments.of("http://example.com:8080", true),
- Arguments.of("http://sub.example.com:8080", true),
- Arguments.of(":8080", false),
- Arguments.of("http://localhost", true),
- Arguments.of("sub.example.com:8080", true),
- Arguments.of("https://username:password@sub.example.com:8080", true),
- Arguments.of("https://username:password@sub.example.com", true)
+ Arguments.of("http://localhost:8080"),
+ Arguments.of("localhost:8080"),
+ Arguments.of("localhost_8080"),
+ Arguments.of("http://example.com:8080"),
+ Arguments.of("http://sub.example.com:8080"),
+ Arguments.of(":8080"),
+ Arguments.of("http://localhost"),
+ Arguments.of("sub.example.com:8080"),
+ Arguments.of("https://username:password@sub.example.com:8080"),
+ Arguments.of("https://username:password@sub.example.com")
);
}
From 6e3a41560ae73e5c879cd388339788f7bd726925 Mon Sep 17 00:00:00 2001
From: Anu Thomas Chandy
Date: Mon, 31 Oct 2022 10:53:02 -0700
Subject: [PATCH 18/46] Ensuring Websocket upgrade request's hostname is the
same as the HTTP host, enabling HTTP Proxy for custom endpoint, and ensuring
Proxy CONNECT request uses the actual front-end host. (#31829)
* Ensuring Websocket upgrade request's hostname is the same as the HTTP host, enabling HTTP Proxy for custom endpoint, and ensuring Proxy CONNECT request uses the actual front-end host.
* Code Reviews: using consistent var name 'hostname', adding unit tests to validate the connect hostname:port pair
* Cleanup proxy tests and added tests to validate hostname for websocket configure
* consistency in hostname
* consistency in hostname
---
eng/versioning/version_client.txt | 1 +
sdk/core/azure-core-amqp/CHANGELOG.md | 3 +
.../ReactorHandlerProvider.java | 8 ---
.../handler/WebSocketsConnectionHandler.java | 19 +++--
.../WebSocketsProxyConnectionHandler.java | 34 ++++++---
.../WebSocketsConnectionHandlerTest.java | 58 ++++++++++++++-
.../WebSocketsProxyConnectionHandlerTest.java | 71 +++++++++++++++++++
.../azure-messaging-eventhubs/pom.xml | 2 +-
.../azure-messaging-servicebus/pom.xml | 2 +-
9 files changed, 171 insertions(+), 27 deletions(-)
diff --git a/eng/versioning/version_client.txt b/eng/versioning/version_client.txt
index dae5959a385a..bb7b88dfbaa1 100644
--- a/eng/versioning/version_client.txt
+++ b/eng/versioning/version_client.txt
@@ -398,6 +398,7 @@ unreleased_com.azure:azure-identity;1.7.0-beta.2
unreleased_com.azure:azure-identity-providers-core;1.0.0-beta.2
unreleased_com.azure:azure-identity-providers-jdbc-mysql;1.0.0-beta.2
unreleased_com.azure:azure-identity-providers-jdbc-postgresql;1.0.0-beta.2
+unreleased_com.azure:azure-core-amqp;2.8.0-beta.1
# Released Beta dependencies: Copy the entry from above, prepend "beta_", remove the current
# version and set the version to the released beta. Released beta dependencies are only valid
diff --git a/sdk/core/azure-core-amqp/CHANGELOG.md b/sdk/core/azure-core-amqp/CHANGELOG.md
index 7222af642092..317c8be2faa8 100644
--- a/sdk/core/azure-core-amqp/CHANGELOG.md
+++ b/sdk/core/azure-core-amqp/CHANGELOG.md
@@ -8,6 +8,9 @@
### Bugs Fixed
+- Updating the host value for the Websocket upgrade request to match with the HTTP host ([31825](https://github.com/Azure/azure-sdk-for-java/issues/31825))
+- Enabling HTTP Proxy for custom endpoint and updating Proxy CONNECT request to use the actual front-end host ([31826](https://github.com/Azure/azure-sdk-for-java/issues/31826))
+
### Other Changes
## 2.7.2 (2022-10-07)
diff --git a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/ReactorHandlerProvider.java b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/ReactorHandlerProvider.java
index 31a659a20884..3cbebb3d5df5 100644
--- a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/ReactorHandlerProvider.java
+++ b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/ReactorHandlerProvider.java
@@ -92,14 +92,6 @@ public ConnectionHandler createConnectionHandler(String connectionId, Connection
final boolean isSystemProxyConfigured = WebSocketsProxyConnectionHandler.shouldUseProxy(
options.getFullyQualifiedNamespace(), options.getPort());
- // TODO (conniey): See if we this is supported later on.
- if (isCustomEndpointConfigured && (isUserProxyConfigured || isSystemProxyConfigured)) {
- throw LOGGER.logExceptionAsError(new UnsupportedOperationException(String.format(
- "Unable to proxy connection to custom endpoint. Custom endpoint: %s. Proxy settings: %s. "
- + "Namespace: %s", options.getHostname(), options.getProxyOptions().getProxyAddress(),
- options.getFullyQualifiedNamespace())));
- }
-
if (isUserProxyConfigured) {
LOGGER.info("Using user configured proxy to connect to: '{}:{}'. Proxy: {}",
options.getFullyQualifiedNamespace(), options.getPort(), options.getProxyOptions().getProxyAddress());
diff --git a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/handler/WebSocketsConnectionHandler.java b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/handler/WebSocketsConnectionHandler.java
index f26271aaed8c..ef111dcd5a67 100644
--- a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/handler/WebSocketsConnectionHandler.java
+++ b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/handler/WebSocketsConnectionHandler.java
@@ -24,6 +24,16 @@ public class WebSocketsConnectionHandler extends ConnectionHandler {
private static final String SOCKET_PATH = "/$servicebus/websocket";
private static final String PROTOCOL = "AMQPWSB10";
+ /**
+ * Once there is an HTTP Connection to the host addressable by https://hostname
+ * (connection the client 'directly' established or established by tunneling through
+ * Proxy etc..), the WebSocket layer has to send an Upgrade request (GET https://hostname)
+ * with upgrade-specific headers to switch from HTTP to WebSocket protocol.
+ * The hostname is the FQDN of the Event Hubs or Service Bus or host part of
+ * CustomEndpointAddress when a custom endpoint frontends the Event Hubs or Service Bus.
+ * The upgrade request will have an HTTP 'Host' header with value as hostname.
+ */
+ private final String hostname;
/**
* Creates a handler that handles proton-j's connection events using web sockets.
@@ -31,9 +41,9 @@ public class WebSocketsConnectionHandler extends ConnectionHandler {
* @param connectionId Identifier for this connection.
* @param connectionOptions Options used when creating the connection.
*/
- public WebSocketsConnectionHandler(String connectionId, ConnectionOptions connectionOptions,
- SslPeerDetails peerDetails, AmqpMetricsProvider metricsProvider) {
+ public WebSocketsConnectionHandler(String connectionId, ConnectionOptions connectionOptions, SslPeerDetails peerDetails, AmqpMetricsProvider metricsProvider) {
super(connectionId, connectionOptions, peerDetails, metricsProvider);
+ this.hostname = connectionOptions.getHostname();
}
/**
@@ -44,11 +54,10 @@ public WebSocketsConnectionHandler(String connectionId, ConnectionOptions connec
*/
@Override
protected void addTransportLayers(final Event event, final TransportInternal transport) {
- final String hostName = event.getConnection().getHostname();
logger.info("Adding web socket layer");
final WebSocketImpl webSocket = new WebSocketImpl();
webSocket.configure(
- hostName,
+ hostname,
SOCKET_PATH,
"",
0,
@@ -59,7 +68,7 @@ protected void addTransportLayers(final Event event, final TransportInternal tra
transport.addTransportLayer(webSocket);
logger.atVerbose()
- .addKeyValue(HOSTNAME_KEY, hostName)
+ .addKeyValue(HOSTNAME_KEY, hostname)
.log("Adding web sockets transport layer.");
super.addTransportLayers(event, transport);
diff --git a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/handler/WebSocketsProxyConnectionHandler.java b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/handler/WebSocketsProxyConnectionHandler.java
index 8a0dcd27096e..9b6709a0d942 100644
--- a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/handler/WebSocketsProxyConnectionHandler.java
+++ b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/handler/WebSocketsProxyConnectionHandler.java
@@ -39,10 +39,23 @@
public class WebSocketsProxyConnectionHandler extends WebSocketsConnectionHandler {
private static final String HTTPS_URI_FORMAT = "https://%s:%s";
- private final InetSocketAddress connectionHostname;
+ private final InetSocketAddress proxyHostAddress;
private final ProxyOptions proxyOptions;
private final String fullyQualifiedNamespace;
- private final String amqpBrokerHostname;
+ /**
+ * The value of 'hostname:port' field for the 'HTTP CONNECT hostname:port HTTP/1.1'
+ * request to the Proxy.
+ * e.g.
+ * CONNECT <eventubs-namespace>.servicebus.windows.net:443 HTTP/1.1
+ * CONNECT order-events.contoso.com:443 HTTP/1.1
+ * CONNECT shipping-events.contoso.com:200 HTTP/1.1
+ *
+ * The 'hostname' addresses the target host to which the HTTP Proxy server should forward
+ * the connection. It is usually the FQDN of the Event Hubs or Service Bus, or the host
+ * part of CustomEndpointAddress when a custom endpoint frontends the Event Hubs
+ * or Service Bus.
+ */
+ private final String connectHostnameAndPort;
/**
* Creates a handler that handles proton-j's connection through a proxy using web sockets.
@@ -61,9 +74,10 @@ public WebSocketsProxyConnectionHandler(String connectionId, ConnectionOptions c
this.proxyOptions = Objects.requireNonNull(proxyOptions, "'proxyConfiguration' cannot be null.");
this.fullyQualifiedNamespace = connectionOptions.getFullyQualifiedNamespace();
- this.amqpBrokerHostname = connectionOptions.getFullyQualifiedNamespace() + ":" + connectionOptions.getPort();
+ this.connectHostnameAndPort = connectionOptions.getHostname() + ":" + connectionOptions.getPort();
+
if (proxyOptions.isProxyAddressConfigured()) {
- this.connectionHostname = (InetSocketAddress) proxyOptions.getProxyAddress().address();
+ this.proxyHostAddress = (InetSocketAddress) proxyOptions.getProxyAddress().address();
} else {
final URI serviceUri = createURI(connectionOptions.getHostname(), connectionOptions.getPort());
final ProxySelector proxySelector = ProxySelector.getDefault();
@@ -80,7 +94,7 @@ public WebSocketsProxyConnectionHandler(String connectionId, ConnectionOptions c
}
final Proxy proxy = proxies.get(0);
- this.connectionHostname = (InetSocketAddress) proxy.address();
+ this.proxyHostAddress = (InetSocketAddress) proxy.address();
}
}
@@ -112,7 +126,7 @@ public static boolean shouldUseProxy(final String hostname, final int port) {
*/
@Override
public String getHostname() {
- return connectionHostname.getHostString();
+ return proxyHostAddress.getHostString();
}
/**
@@ -122,7 +136,7 @@ public String getHostname() {
*/
@Override
public int getProtocolPort() {
- return connectionHostname.getPort();
+ return proxyHostAddress.getPort();
}
@Override
@@ -192,15 +206,13 @@ protected void addTransportLayers(final Event event, final TransportInternal tra
? new ProxyImpl(getProtonConfiguration())
: new ProxyImpl();
- // host name used to create proxy connect request must contain a port number.
- // after creating the socket to proxy
final ProxyHandler proxyHandler = new ProxyHandlerImpl();
- proxy.configure(amqpBrokerHostname, null, proxyHandler, transport);
+ proxy.configure(connectHostnameAndPort, null, proxyHandler, transport);
transport.addTransportLayer(proxy);
logger.atInfo()
- .addKeyValue(HOSTNAME_KEY, amqpBrokerHostname)
+ .addKeyValue(HOSTNAME_KEY, connectHostnameAndPort)
.log("addProxyHandshake");
}
diff --git a/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/handler/WebSocketsConnectionHandlerTest.java b/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/handler/WebSocketsConnectionHandlerTest.java
index dab9a04e460c..0dd519348e05 100644
--- a/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/handler/WebSocketsConnectionHandlerTest.java
+++ b/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/handler/WebSocketsConnectionHandlerTest.java
@@ -15,6 +15,7 @@
import com.azure.core.test.utils.metrics.TestMeasurement;
import com.azure.core.test.utils.metrics.TestMeter;
import com.azure.core.util.ClientOptions;
+import com.microsoft.azure.proton.transport.ws.impl.WebSocketImpl;
import org.apache.qpid.proton.Proton;
import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.transport.ErrorCondition;
@@ -23,6 +24,7 @@
import org.apache.qpid.proton.engine.Event;
import org.apache.qpid.proton.engine.SslDomain;
import org.apache.qpid.proton.engine.SslPeerDetails;
+import org.apache.qpid.proton.engine.impl.TransportImpl;
import org.apache.qpid.proton.engine.impl.TransportInternal;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
@@ -31,6 +33,7 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
+import org.mockito.MockedConstruction;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import reactor.core.scheduler.Scheduler;
@@ -46,7 +49,9 @@
import static com.azure.core.amqp.implementation.handler.WebSocketsConnectionHandler.MAX_FRAME_SIZE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -54,7 +59,7 @@ public class WebSocketsConnectionHandlerTest {
private static final ClientOptions CLIENT_OPTIONS = new ClientOptions();
private static final String CONNECTION_ID = "some-random-id";
private static final String HOSTNAME = "hostname-random";
-
+ private static final String CUSTOM_ENDPOINT_HOSTNAME = "custom-hostname-random";
private static final SslDomain.VerifyMode VERIFY_MODE = SslDomain.VerifyMode.VERIFY_PEER_NAME;
private static final String PRODUCT = "my-product";
private static final String CLIENT_VERSION = "1.5.1-alpha";
@@ -224,6 +229,57 @@ AmqpTransportType.AMQP_WEB_SOCKETS, new AmqpRetryOptions(), ProxyOptions.SYSTEM_
}
}
+ @Test
+ public void websocketConfigureUsesFqdnAsHostname() {
+ try (MockedConstruction mockConstruction = mockConstruction(WebSocketImpl.class)) {
+ handler.addTransportLayers(mock(Event.class, Mockito.CALLS_REAL_METHODS),
+ mock(TransportImpl.class, Mockito.CALLS_REAL_METHODS));
+
+ final List constructed = mockConstruction.constructed();
+ assertEquals(1, constructed.size());
+ // The WebSocketImpl object constructed inside addTransportLayer method.
+ final WebSocketImpl webSocketImpl = constructed.get(0);
+ final String expectedHostName = HOSTNAME;
+ verify(webSocketImpl).configure(eq(expectedHostName),
+ eq("/$servicebus/websocket"),
+ eq(""),
+ eq(0),
+ eq("AMQPWSB10"),
+ eq(null),
+ eq(null));
+ }
+ }
+
+ @Test
+ public void websocketConfigureUsesCustomEndpointHostnameAsHostname() {
+ final String customEndpointHostname = "order-events.contoso.com";
+ final ConnectionOptions connectionOptionsWithCustomEndpoint = new ConnectionOptions(HOSTNAME, tokenCredential,
+ CbsAuthorizationType.SHARED_ACCESS_SIGNATURE, "scope", AmqpTransportType.AMQP_WEB_SOCKETS,
+ new AmqpRetryOptions(), ProxyOptions.SYSTEM_DEFAULTS, scheduler, CLIENT_OPTIONS, VERIFY_MODE, PRODUCT,
+ CLIENT_VERSION, customEndpointHostname, 200);
+
+ try (WebSocketsConnectionHandler handler = new WebSocketsConnectionHandler(CONNECTION_ID,
+ connectionOptionsWithCustomEndpoint,
+ peerDetails, AmqpMetricsProvider.noop())) {
+ try (MockedConstruction mockConstruction = mockConstruction(WebSocketImpl.class)) {
+ handler.addTransportLayers(mock(Event.class, Mockito.CALLS_REAL_METHODS),
+ mock(TransportImpl.class, Mockito.CALLS_REAL_METHODS));
+
+ final List constructed = mockConstruction.constructed();
+ assertEquals(1, constructed.size());
+ // The WebSocketImpl object constructed inside addTransportLayer method.
+ final WebSocketImpl webSocketImpl = constructed.get(0);
+ verify(webSocketImpl).configure(eq(customEndpointHostname),
+ eq("/$servicebus/websocket"),
+ eq(""),
+ eq(0),
+ eq("AMQPWSB10"),
+ eq(null),
+ eq(null));
+ }
+ }
+ }
+
@Test
void onConnectionCloseMetrics() {
// Arrange
diff --git a/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/handler/WebSocketsProxyConnectionHandlerTest.java b/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/handler/WebSocketsProxyConnectionHandlerTest.java
index 3fda65319eab..78cfcb6c197a 100644
--- a/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/handler/WebSocketsProxyConnectionHandlerTest.java
+++ b/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/handler/WebSocketsProxyConnectionHandlerTest.java
@@ -17,6 +17,7 @@
import com.azure.core.test.utils.metrics.TestMeter;
import com.azure.core.util.ClientOptions;
import com.azure.core.util.Header;
+import com.microsoft.azure.proton.transport.proxy.impl.ProxyImpl;
import org.apache.qpid.proton.Proton;
import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.transport.ErrorCondition;
@@ -25,6 +26,7 @@
import org.apache.qpid.proton.engine.Event;
import org.apache.qpid.proton.engine.SslDomain;
import org.apache.qpid.proton.engine.SslPeerDetails;
+import org.apache.qpid.proton.engine.impl.TransportImpl;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@@ -33,6 +35,7 @@
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.junit.jupiter.api.parallel.Isolated;
import org.mockito.Mock;
+import org.mockito.MockedConstruction;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import reactor.core.scheduler.Scheduler;
@@ -47,7 +50,9 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
@@ -57,6 +62,7 @@
public class WebSocketsProxyConnectionHandlerTest {
private static final String CONNECTION_ID = "some-connection-id";
private static final String HOSTNAME = "event-hubs.windows.core.net";
+ private static final int AMQP_PORT = 5671;
private static final InetSocketAddress PROXY_ADDRESS = InetSocketAddress.createUnresolved("foo.proxy.com", 3138);
private static final Proxy PROXY = new Proxy(Proxy.Type.HTTP, PROXY_ADDRESS);
private static final String USERNAME = "test-user";
@@ -188,6 +194,71 @@ public void proxyConfigurationSelected() {
verifyNoInteractions(proxySelector);
}
+ /**
+ * Verifies that the hostname:port for Proxy CONNECT created from
+ * the FQDN host field in {@link ConnectionOptions}.
+ */
+ @Test
+ public void proxyConfigureConnectHostnameAndPortDerivesFromFqdn() {
+ // Arrange
+ final InetSocketAddress address = InetSocketAddress.createUnresolved("my-new.proxy.com", 8888);
+ final Proxy newProxy = new Proxy(Proxy.Type.HTTP, address);
+ final ProxyOptions proxyOptions = new ProxyOptions(ProxyAuthenticationType.BASIC, newProxy, USERNAME,
+ PASSWORD);
+
+ this.handler = new WebSocketsProxyConnectionHandler(CONNECTION_ID, connectionOptions,
+ proxyOptions, peerDetails, AmqpMetricsProvider.noop());
+
+ // Act and Assert
+ try (MockedConstruction mockConstruction = mockConstruction(ProxyImpl.class)) {
+ this.handler.addTransportLayers(mock(Event.class, Mockito.CALLS_REAL_METHODS),
+ mock(TransportImpl.class, Mockito.CALLS_REAL_METHODS));
+
+ final List constructed = mockConstruction.constructed();
+ assertEquals(1, constructed.size());
+ // The ProxyImpl object constructed inside addTransportLayer method.
+ final ProxyImpl proxyImpl = constructed.get(0);
+ final String expectedConnectHostnameAndPort = HOSTNAME + ":" + AMQP_PORT;
+ verify(proxyImpl).configure(eq(expectedConnectHostnameAndPort), any(), any(), any());
+ }
+ }
+
+ /**
+ * Verifies that the hostname:port for Proxy CONNECT created from
+ * the Custom host fields in {@link ConnectionOptions}.
+ */
+ @Test
+ public void proxyConfigureConnectHostnameAndPortDerivesFromCustomEndpoint() {
+ // Arrange
+ final InetSocketAddress address = InetSocketAddress.createUnresolved("my-new.proxy.com", 8888);
+ final Proxy newProxy = new Proxy(Proxy.Type.HTTP, address);
+ final ProxyOptions proxyOptions = new ProxyOptions(ProxyAuthenticationType.BASIC, newProxy, USERNAME,
+ PASSWORD);
+ final String customEndpointHostname = "order-events.contoso.com";
+ final int customEndpointPort = 200;
+
+ final ConnectionOptions connectionOptionsWithCustomEndpoint = new ConnectionOptions(HOSTNAME, tokenCredential,
+ CbsAuthorizationType.SHARED_ACCESS_SIGNATURE, "scope", AmqpTransportType.AMQP_WEB_SOCKETS,
+ new AmqpRetryOptions(), ProxyOptions.SYSTEM_DEFAULTS, scheduler, CLIENT_OPTIONS, VERIFY_MODE, PRODUCT,
+ CLIENT_VERSION, customEndpointHostname, customEndpointPort);
+
+ this.handler = new WebSocketsProxyConnectionHandler(CONNECTION_ID, connectionOptionsWithCustomEndpoint,
+ proxyOptions, peerDetails, AmqpMetricsProvider.noop());
+
+ // Act and Assert
+ try (MockedConstruction mockConstruction = mockConstruction(ProxyImpl.class)) {
+ this.handler.addTransportLayers(mock(Event.class, Mockito.CALLS_REAL_METHODS),
+ mock(TransportImpl.class, Mockito.CALLS_REAL_METHODS));
+
+ final List constructed = mockConstruction.constructed();
+ assertEquals(1, constructed.size());
+ // The ProxyImpl object constructed inside addTransportLayer method.
+ final ProxyImpl proxyImpl = constructed.get(0);
+ final String expectedConnectHostnameAndPort = customEndpointHostname + ":" + customEndpointPort;
+ verify(proxyImpl).configure(eq(expectedConnectHostnameAndPort), any(), any(), any());
+ }
+ }
+
@Test
public void shouldUseProxyNoLegalProxyAddress() {
// Arrange
diff --git a/sdk/eventhubs/azure-messaging-eventhubs/pom.xml b/sdk/eventhubs/azure-messaging-eventhubs/pom.xml
index a0ad13fc6fe3..e67a094841a0 100644
--- a/sdk/eventhubs/azure-messaging-eventhubs/pom.xml
+++ b/sdk/eventhubs/azure-messaging-eventhubs/pom.xml
@@ -42,7 +42,7 @@
com.azure
azure-core-amqp
- 2.7.2
+ 2.8.0-beta.1
diff --git a/sdk/servicebus/azure-messaging-servicebus/pom.xml b/sdk/servicebus/azure-messaging-servicebus/pom.xml
index b2590f37c67f..33649444b307 100644
--- a/sdk/servicebus/azure-messaging-servicebus/pom.xml
+++ b/sdk/servicebus/azure-messaging-servicebus/pom.xml
@@ -55,7 +55,7 @@
com.azure
azure-core-amqp
- 2.7.2
+ 2.8.0-beta.1
com.azure
From 5bdf09aceac5e4cce4c6def23b0214d7cf3644e6 Mon Sep 17 00:00:00 2001
From: Liudmila Molkova
Date: Mon, 31 Oct 2022 12:00:34 -0700
Subject: [PATCH 19/46] Tracing for eventhubs consumer and batch processor
(#31197)
* Trace eventhubs consumer and batch processor
---
.../checkstyle/checkstyle-suppressions.xml | 1 +
.../implementation/AmqpMetricsProvider.java | 8 +
.../RequestResponseChannel.java | 4 +-
.../amqp/implementation/TracerProvider.java | 4 +
.../implementation/TracerProviderTest.java | 1 +
.../README.md | 11 +-
.../azure-core-tracing-opentelemetry/pom.xml | 6 -
.../opentelemetry/OpenTelemetryTracer.java | 46 +-
.../OpenTelemetryTracerTest.java | 53 +-
.../azure-messaging-eventhubs/CHANGELOG.md | 2 +
.../azure-messaging-eventhubs/pom.xml | 22 +
.../messaging/eventhubs/EventDataBatch.java | 69 +--
.../eventhubs/EventHubAsyncClient.java | 24 +-
.../EventHubBufferedPartitionProducer.java | 8 +-
.../EventHubBufferedProducerAsyncClient.java | 9 +-
...EventHubBufferedProducerClientBuilder.java | 3 +-
.../messaging/eventhubs/EventHubClient.java | 2 +-
.../eventhubs/EventHubClientBuilder.java | 18 +-
.../EventHubConsumerAsyncClient.java | 29 +-
.../eventhubs/EventHubConsumerClient.java | 15 +-
.../eventhubs/EventHubMessageSerializer.java | 13 +-
.../EventHubProducerAsyncClient.java | 104 +---
.../eventhubs/EventHubProducerClient.java | 1 +
.../EventHubsProducerInstrumentation.java | 64 +++
.../eventhubs/EventProcessorClient.java | 13 +-
.../EventProcessorClientBuilder.java | 10 +-
.../eventhubs/PartitionPumpManager.java | 109 +---
.../AmqpReceiveLinkProcessor.java | 16 +-
.../{ => implementation}/MessageUtils.java | 32 +-
.../EventHubsConsumerInstrumentation.java | 49 ++
.../EventHubsMetricsProvider.java | 23 +-
.../instrumentation/EventHubsTracer.java | 255 +++++++++
...EventsTracingWithCustomContextSample.java} | 58 +-
.../EventDataBatchIntegrationTest.java | 12 +-
.../eventhubs/EventDataBatchTest.java | 13 +-
...EventHubBufferedPartitionProducerTest.java | 12 +-
.../EventHubConsumerAsyncClientTest.java | 127 ++++-
.../eventhubs/EventHubConsumerClientTest.java | 12 +-
.../EventHubPartitionAsyncConsumerTest.java | 10 +-
.../EventHubProducerAsyncClientTest.java | 184 ++++--
.../eventhubs/EventHubProducerClientTest.java | 58 +-
.../EventProcessorClientBuilderTest.java | 1 +
...EventProcessorClientErrorHandlingTest.java | 43 +-
.../eventhubs/EventProcessorClientTest.java | 224 +++++---
.../messaging/eventhubs/MessageUtilsTest.java | 1 +
.../PartitionBasedLoadBalancerTest.java | 55 +-
.../eventhubs/PartitionPumpManagerTest.java | 19 +-
.../eventhubs/TracingIntegrationTests.java | 537 ++++++++++++++++++
.../AmqpReceiveLinkProcessorTest.java | 11 +-
49 files changed, 1804 insertions(+), 597 deletions(-)
create mode 100644 sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubsProducerInstrumentation.java
rename sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/{ => implementation}/MessageUtils.java (90%)
create mode 100644 sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/instrumentation/EventHubsConsumerInstrumentation.java
rename sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/{ => instrumentation}/EventHubsMetricsProvider.java (86%)
create mode 100644 sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/instrumentation/EventHubsTracer.java
rename sdk/{core/azure-core-tracing-opentelemetry/src/samples/java/com/azure/core/tracing/opentelemetry/PublishEventsJaegerExporterSample.java => eventhubs/azure-messaging-eventhubs/src/samples/java/com/azure/messaging/eventhubs/PublishEventsTracingWithCustomContextSample.java} (68%)
create mode 100644 sdk/eventhubs/azure-messaging-eventhubs/src/test/java/com/azure/messaging/eventhubs/TracingIntegrationTests.java
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 0e7e17602cf5..a8c399de6de0 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
@@ -100,6 +100,7 @@
+
diff --git a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/AmqpMetricsProvider.java b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/AmqpMetricsProvider.java
index 83a395728e1a..81343230340a 100644
--- a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/AmqpMetricsProvider.java
+++ b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/AmqpMetricsProvider.java
@@ -146,6 +146,14 @@ public boolean isSendDeliveryEnabled() {
return isEnabled && sendDuration.isEnabled();
}
+ /**
+ * Checks if request-response duration metric is enabled (for micro-optimizations).
+ */
+ public boolean isRequestResponseDurationEnabled() {
+ return isEnabled && sendDuration.isEnabled();
+ }
+
+
/**
* Checks if prefetched sequence number is enabled (for micro-optimizations).
*/
diff --git a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/RequestResponseChannel.java b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/RequestResponseChannel.java
index ca062ec23ce8..830e691c525b 100644
--- a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/RequestResponseChannel.java
+++ b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/RequestResponseChannel.java
@@ -504,7 +504,7 @@ private void terminateUnconfirmedSends(Throwable error) {
* Captures current time in mono context - used to report send metric
*/
private Mono captureStartTime(Message toSend, Mono publisher) {
- if (metricsProvider.isSendDeliveryEnabled()) {
+ if (metricsProvider.isRequestResponseDurationEnabled()) {
String operationName = "unknown";
if (toSend != null && toSend.getApplicationProperties() != null && toSend.getApplicationProperties().getValue() != null) {
Map properties = toSend.getApplicationProperties().getValue();
@@ -532,7 +532,7 @@ private static ContextView getSinkContext(MonoSink> sink) {
* Records send call duration metric.
**/
private void recordDelivery(ContextView context, Message response) {
- if (metricsProvider.isSendDeliveryEnabled()) {
+ if (metricsProvider.isRequestResponseDurationEnabled()) {
Object startTimestamp = context.getOrDefault(START_SEND_TIME_CONTEXT_KEY, null);
Object operationName = context.getOrDefault(OPERATION_CONTEXT_KEY, null);
AmqpResponseCode responseCode = response == null ? null : RequestResponseUtils.getStatusCode(response);
diff --git a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/TracerProvider.java b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/TracerProvider.java
index d697d3f08351..18ef80818900 100644
--- a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/TracerProvider.java
+++ b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/TracerProvider.java
@@ -11,6 +11,10 @@
import java.util.Objects;
+@Deprecated
+/**
+ * @deprecated use EventHubs*Tracer and ServiceBus*Tracer instead.
+ */
public class TracerProvider {
private static final ClientLogger LOGGER = new ClientLogger(TracerProvider.class);
private Tracer tracer;
diff --git a/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/TracerProviderTest.java b/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/TracerProviderTest.java
index bf3c6882553d..bf83b1ac227e 100644
--- a/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/TracerProviderTest.java
+++ b/sdk/core/azure-core-amqp/src/test/java/com/azure/core/amqp/implementation/TracerProviderTest.java
@@ -31,6 +31,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+@SuppressWarnings("deprecation")
public class TracerProviderTest {
private static final String SERVICE_BASE_NAME = "serviceBaseName";
private static final String METHOD_NAME = SERVICE_BASE_NAME + "send";
diff --git a/sdk/core/azure-core-tracing-opentelemetry/README.md b/sdk/core/azure-core-tracing-opentelemetry/README.md
index a83f28d577ee..392836e7ff55 100644
--- a/sdk/core/azure-core-tracing-opentelemetry/README.md
+++ b/sdk/core/azure-core-tracing-opentelemetry/README.md
@@ -122,9 +122,13 @@ try {
Send a single event/message using [azure-messaging-eventhubs][azure-messaging-eventhubs] with tracing enabled.
-Users can additionally pass the value of the current tracing span to the EventData object with key **PARENT_TRACE_CONTEXT_KEY** on the [Context][context] object:
+Users can additionally pass custom value of the trace context to the EventData object with key **PARENT_TRACE_CONTEXT_KEY** on the [Context][context] object.
+
+Please refer to [Event Hubs samples][event_hubs_samples]
+for more information.
+
+```java
-```java readme-sample-context-manual-propagation-amqp
Flux events = Flux.just(
new EventData("EventData Sample 1"),
new EventData("EventData Sample 2"));
@@ -151,6 +155,7 @@ events.collect(batchRef::get, (b, e) ->
return ctx.put(PARENT_TRACE_CONTEXT_KEY, traceContextRef.updateAndGet(traceContext -> traceContext.with(span)));
})
.block();
+
```
## Troubleshooting
@@ -203,9 +208,9 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
[OpenTelemetry]: https://github.com/open-telemetry/opentelemetry-java#opentelemetry-for-java
[sample_app_config]: https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/core/azure-core-tracing-opentelemetry/src/samples/java/com/azure/core/tracing/opentelemetry/CreateConfigurationSettingLoggingExporterSample.java
[sample_async_key_vault]: https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/core/azure-core-tracing-opentelemetry/src/samples/java/com/azure/core/tracing/opentelemetry/ListKeyVaultSecretsAutoConfigurationSample.java
-[sample_eventhubs]: https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/core/azure-core-tracing-opentelemetry/src/samples/java/com/azure/core/tracing/opentelemetry/PublishEventsJaegerExporterSample.java
[sample_key_vault]: https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/core/azure-core-tracing-opentelemetry/src/samples/java/com/azure/core/tracing/opentelemetry/ListKeyVaultSecretsJaegerExporterSample.java
[samples]: https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/core/azure-core-tracing-opentelemetry/src/samples/
[source_code]: https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/core/azure-core-tracing-opentelemetry/src
+[event_hubs_samples](https://github.com/Azure/azure-sdk-for-java/blob/10a18ccc2f20cad6004ae90d64f22009d65e9ef7/sdk/eventhubs/azure-messaging-eventhubs/src/samples/java/com/azure/messaging/eventhubs/PublishEventsTracingWithCustomContextSample.java)

diff --git a/sdk/core/azure-core-tracing-opentelemetry/pom.xml b/sdk/core/azure-core-tracing-opentelemetry/pom.xml
index 01166a6b48cd..f2d26fb8af42 100644
--- a/sdk/core/azure-core-tracing-opentelemetry/pom.xml
+++ b/sdk/core/azure-core-tracing-opentelemetry/pom.xml
@@ -134,12 +134,6 @@
1.6.1
test
-
- com.azure
- azure-messaging-eventhubs
- 5.14.0
- test
-
io.opentelemetry
opentelemetry-sdk-extension-autoconfigure
diff --git a/sdk/core/azure-core-tracing-opentelemetry/src/main/java/com/azure/core/tracing/opentelemetry/OpenTelemetryTracer.java b/sdk/core/azure-core-tracing-opentelemetry/src/main/java/com/azure/core/tracing/opentelemetry/OpenTelemetryTracer.java
index 1a1b34f4ffac..daab2c7b12b4 100644
--- a/sdk/core/azure-core-tracing-opentelemetry/src/main/java/com/azure/core/tracing/opentelemetry/OpenTelemetryTracer.java
+++ b/sdk/core/azure-core-tracing-opentelemetry/src/main/java/com/azure/core/tracing/opentelemetry/OpenTelemetryTracer.java
@@ -22,6 +22,7 @@
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
+import java.time.Instant;
import java.time.OffsetDateTime;
import java.util.Map;
import java.util.Objects;
@@ -36,6 +37,8 @@
*/
public class OpenTelemetryTracer implements com.azure.core.util.tracing.Tracer {
private static final StartSpanOptions DEFAULT_OPTIONS = new StartSpanOptions(com.azure.core.util.tracing.SpanKind.INTERNAL);
+ private static final String SPAN_KIND_KEY = "span-kind";
+ private static final String START_TIME_KEY = "span-start-time";
private final Tracer tracer;
/**
@@ -65,7 +68,7 @@ public OpenTelemetryTracer() {
private static final ClientLogger LOGGER = new ClientLogger(OpenTelemetryTracer.class);
private static final AutoCloseable NOOP_CLOSEABLE = () -> { };
- private static final SpanKind SHARED_SPAN_BUILDER_KIND = SpanKind.CLIENT;
+ private static final SpanKind DEFAULT_SHARED_SPAN_BUILDER_KIND = SpanKind.CLIENT;
private static final String SUPPRESSED_SPAN_FLAG = "suppressed-span-flag";
private static final String CLIENT_METHOD_CALL_FLAG = "client-method-call-flag";
@@ -114,7 +117,7 @@ public Context start(String spanName, Context context, ProcessKind processKind)
context = unsuppress(context);
switch (processKind) {
case SEND:
- // use previously created span builder from the LINK process.
+ // use previously created span builder with the links
spanBuilder = getOrNull(context, SPAN_BUILDER_KEY, SpanBuilder.class);
if (spanBuilder == null) {
// we can't return context here, because caller would not know that span was not created.
@@ -123,17 +126,23 @@ public Context start(String spanName, Context context, ProcessKind processKind)
.addKeyValue("spanName", spanName)
.addKeyValue("processKind", processKind)
.log("Start span is called without builder on the context, creating default builder.");
- spanBuilder = createSpanBuilder(spanName, null, SHARED_SPAN_BUILDER_KIND, null, context);
+ spanBuilder = createSpanBuilder(spanName, null, SpanKind.CLIENT, null, context);
}
- return startSpanInternal(spanBuilder, isClientCall(SHARED_SPAN_BUILDER_KIND), this::addMessagingAttributes, context);
+ return startSpanInternal(spanBuilder, true, this::addMessagingAttributes, context);
case MESSAGE:
spanBuilder = createSpanBuilder(spanName, null, SpanKind.PRODUCER, null, context);
context = startSpanInternal(spanBuilder, false, this::addMessagingAttributes, context);
return setDiagnosticId(context);
case PROCESS:
- SpanContext remoteParentContext = getOrNull(context, SPAN_CONTEXT_KEY, SpanContext.class);
- spanBuilder = createSpanBuilder(spanName, remoteParentContext, SpanKind.CONSUMER, null, context);
+ // use previously created span builder with the links
+ spanBuilder = getOrNull(context, SPAN_BUILDER_KEY, SpanBuilder.class);
+ if (spanBuilder == null) {
+ // if there is no builder, create new one from parent in context
+ SpanContext remoteParentContext = getOrNull(context, SPAN_CONTEXT_KEY, SpanContext.class);
+ spanBuilder = createSpanBuilder(spanName, remoteParentContext, SpanKind.CONSUMER, null, context);
+ }
+
context = startSpanInternal(spanBuilder, false, this::addMessagingAttributes, context);
// TODO (limolkova) we should do this in the EventHub/ServiceBus SDK instead to make sure scope is
@@ -227,7 +236,14 @@ public void addLink(Context context) {
if (spanContext == null) {
return;
}
- spanBuilder.addLink(spanContext);
+
+ Attributes linkAttributes = Attributes.empty();
+ Long messageEnqueuedTime = getOrNull(context, MESSAGE_ENQUEUED_TIME, Long.class);
+ if (messageEnqueuedTime != null) {
+ linkAttributes = Attributes.of(AttributeKey.longKey(MESSAGE_ENQUEUED_TIME), messageEnqueuedTime);
+ }
+
+ spanBuilder.addLink(spanContext, linkAttributes);
}
/**
@@ -243,8 +259,18 @@ public Context extractContext(String diagnosticId, Context context) {
*/
@Override
public Context getSharedSpanBuilder(String spanName, Context context) {
- // this is used to create messaging send spanBuilder, and it's a CLIENT span
- return context.addData(SPAN_BUILDER_KEY, createSpanBuilder(spanName, null, SHARED_SPAN_BUILDER_KIND, null, context));
+ com.azure.core.util.tracing.SpanKind spanKind = getOrNull(context, SPAN_KIND_KEY, com.azure.core.util.tracing.SpanKind.class);
+ if (spanKind == null) {
+ spanKind = com.azure.core.util.tracing.SpanKind.CLIENT;
+ }
+
+ SpanBuilder builder = createSpanBuilder(spanName, null, convertToOtelKind(spanKind), null, context);
+ Instant startTime = getOrNull(context, START_TIME_KEY, Instant.class);
+ if (startTime != null) {
+ builder.setStartTimestamp(startTime);
+ }
+
+ return context.addData(SPAN_BUILDER_KEY, builder);
}
/**
@@ -563,7 +589,7 @@ private Span getSpanOrNull(Context azContext) {
private SpanKind processKindToSpanKind(ProcessKind processKind) {
switch (processKind) {
case SEND:
- return SHARED_SPAN_BUILDER_KIND;
+ return SpanKind.CLIENT;
case MESSAGE:
return SpanKind.PRODUCER;
case PROCESS:
diff --git a/sdk/core/azure-core-tracing-opentelemetry/src/test/java/com/azure/core/tracing/opentelemetry/OpenTelemetryTracerTest.java b/sdk/core/azure-core-tracing-opentelemetry/src/test/java/com/azure/core/tracing/opentelemetry/OpenTelemetryTracerTest.java
index acc2abb97bc4..16c51a5557a0 100644
--- a/sdk/core/azure-core-tracing-opentelemetry/src/test/java/com/azure/core/tracing/opentelemetry/OpenTelemetryTracerTest.java
+++ b/sdk/core/azure-core-tracing-opentelemetry/src/test/java/com/azure/core/tracing/opentelemetry/OpenTelemetryTracerTest.java
@@ -323,6 +323,58 @@ public void startProcessSpanWithRemoteParent() {
assertTrue(updatedContext.getData(SCOPE_KEY).isPresent());
}
+ @Test
+ public void startProcessSpanWithLinks() {
+ // Arrange
+ final Context spanBuilder = openTelemetryTracer.getSharedSpanBuilder("span", Context.NONE);
+
+ Span link1 = tracer.spanBuilder("link1").startSpan();
+ Span link2 = tracer.spanBuilder("link2").startSpan();
+
+ openTelemetryTracer.addLink(spanBuilder.addData(SPAN_CONTEXT_KEY, link1.getSpanContext()));
+ openTelemetryTracer.addLink(spanBuilder
+ .addData(SPAN_CONTEXT_KEY, link2.getSpanContext())
+ .addData(MESSAGE_ENQUEUED_TIME, MESSAGE_ENQUEUED_VALUE));
+
+ // Act
+ final Context spanCtx = openTelemetryTracer.start(METHOD_NAME, spanBuilder, ProcessKind.PROCESS);
+ openTelemetryTracer.end(null, null, spanCtx);
+
+ // Assert
+ ReadableSpan span = getSpan(spanCtx);
+ List links = span.toSpanData().getLinks();
+ assertEquals(2, links.size());
+ assertEquals(link1.getSpanContext().getTraceId(), links.get(0).getSpanContext().getTraceId());
+ assertEquals(link1.getSpanContext().getSpanId(), links.get(0).getSpanContext().getSpanId());
+ assertEquals(0, links.get(0).getAttributes().size());
+
+ assertEquals(link2.getSpanContext().getTraceId(), links.get(1).getSpanContext().getTraceId());
+ assertEquals(link2.getSpanContext().getSpanId(), links.get(1).getSpanContext().getSpanId());
+ Attributes linkAttributes = links.get(1).getAttributes();
+ assertEquals(1, linkAttributes.size());
+ assertEquals(MESSAGE_ENQUEUED_VALUE, linkAttributes.get(AttributeKey.longKey(MESSAGE_ENQUEUED_TIME)));
+ }
+
+ @Test
+ public void startConsumeSpanWitStartTimeInContext() {
+ // Arrange
+ final Context spanBuilder = openTelemetryTracer.getSharedSpanBuilder("span",
+ new Context("span-start-time", Instant.now().minusSeconds(1000)));
+
+ Span link = tracer.spanBuilder("link1").startSpan();
+
+ openTelemetryTracer.addLink(spanBuilder.addData(SPAN_CONTEXT_KEY, link.getSpanContext()));
+
+ // Act
+ final Context spanCtx = openTelemetryTracer.start(METHOD_NAME, spanBuilder, ProcessKind.PROCESS);
+ openTelemetryTracer.end(null, null, spanCtx);
+
+ // Assert
+ ReadableSpan span = getSpan(spanCtx);
+ assertEquals(1, span.toSpanData().getLinks().size());
+ assertEquals(span.getLatencyNanos() / 1000_000_000d, 1000d, 10);
+ }
+
@Test
public void startSpanOverloadNullPointerException() {
@@ -930,7 +982,6 @@ private static Stream spanKinds() {
Arguments.of(com.azure.core.util.tracing.SpanKind.SERVER, com.azure.core.util.tracing.SpanKind.PRODUCER, false),
Arguments.of(com.azure.core.util.tracing.SpanKind.SERVER, com.azure.core.util.tracing.SpanKind.CONSUMER, false),
Arguments.of(com.azure.core.util.tracing.SpanKind.SERVER, com.azure.core.util.tracing.SpanKind.SERVER, false));
-
}
@Test
diff --git a/sdk/eventhubs/azure-messaging-eventhubs/CHANGELOG.md b/sdk/eventhubs/azure-messaging-eventhubs/CHANGELOG.md
index b6be17e5a620..81f515069be3 100644
--- a/sdk/eventhubs/azure-messaging-eventhubs/CHANGELOG.md
+++ b/sdk/eventhubs/azure-messaging-eventhubs/CHANGELOG.md
@@ -14,6 +14,8 @@
### Features Added
+- Enabled metrics for sent events, consumer lag, checkpointing. ([#31024](https://github.com/Azure/azure-sdk-for-java/pull/31024))
+- Enabled distributed tracing for consumer and batch processor. ([#31197](https://github.com/Azure/azure-sdk-for-java/pull/31197))
- Added algorithm for mapping partition keys to partition ids.
- Added EventHubBufferedProducerAsyncClient and EventHubBufferedProducerClient
diff --git a/sdk/eventhubs/azure-messaging-eventhubs/pom.xml b/sdk/eventhubs/azure-messaging-eventhubs/pom.xml
index e67a094841a0..6fa35f034e86 100644
--- a/sdk/eventhubs/azure-messaging-eventhubs/pom.xml
+++ b/sdk/eventhubs/azure-messaging-eventhubs/pom.xml
@@ -89,5 +89,27 @@
4.5.1
test
+
+
+
+ com.azure
+ azure-core-tracing-opentelemetry
+ 1.0.0-beta.29
+ test
+
+
+
+ io.opentelemetry
+ opentelemetry-api
+ 1.14.0
+ test
+
+
+
+ io.opentelemetry
+ opentelemetry-sdk
+ 1.14.0
+ test
+
diff --git a/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventDataBatch.java b/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventDataBatch.java
index 004b0383b480..bd32980557a9 100644
--- a/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventDataBatch.java
+++ b/sdk/eventhubs/azure-messaging-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventDataBatch.java
@@ -7,15 +7,13 @@
import com.azure.core.amqp.exception.AmqpException;
import com.azure.core.amqp.implementation.AmqpConstants;
import com.azure.core.amqp.implementation.ErrorContextProvider;
-import com.azure.core.amqp.implementation.TracerProvider;
import com.azure.core.amqp.models.AmqpAnnotatedMessage;
-import com.azure.core.util.Context;
import com.azure.core.util.logging.ClientLogger;
-import com.azure.core.util.tracing.ProcessKind;
+import com.azure.messaging.eventhubs.implementation.MessageUtils;
+import com.azure.messaging.eventhubs.implementation.instrumentation.EventHubsTracer;
import com.azure.messaging.eventhubs.models.CreateBatchOptions;
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
import org.apache.qpid.proton.message.Message;
-import reactor.core.publisher.Signal;
import java.nio.BufferOverflowException;
import java.util.HashMap;
@@ -23,15 +21,6 @@
import java.util.List;
import java.util.Locale;
import java.util.Objects;
-import java.util.Optional;
-
-import static com.azure.core.util.tracing.Tracer.AZ_TRACING_NAMESPACE_KEY;
-import static com.azure.core.util.tracing.Tracer.DIAGNOSTIC_ID_KEY;
-import static com.azure.core.util.tracing.Tracer.ENTITY_PATH_KEY;
-import static com.azure.core.util.tracing.Tracer.HOST_NAME_KEY;
-import static com.azure.core.util.tracing.Tracer.SPAN_CONTEXT_KEY;
-import static com.azure.messaging.eventhubs.implementation.ClientConstants.AZ_NAMESPACE_VALUE;
-import static com.azure.messaging.eventhubs.implementation.ClientConstants.AZ_TRACING_SERVICE_NAME;
/**
* A class for aggregating {@link EventData} into a single, size-limited, batch. It is treated as a single message when
@@ -53,12 +42,10 @@ public final class EventDataBatch {
private final byte[] eventBytes;
private final String partitionId;
private int sizeInBytes;
- private final TracerProvider tracerProvider;
- private final String entityPath;
- private final String hostname;
+ private final EventHubsTracer tracer;
EventDataBatch(int maxMessageSize, String partitionId, String partitionKey, ErrorContextProvider contextProvider,
- TracerProvider tracerProvider, String entityPath, String hostname) {
+ EventHubsProducerInstrumentation instrumentation) {
this.maxMessageSize = maxMessageSize;
this.partitionKey = partitionKey;
this.partitionId = partitionId;
@@ -66,9 +53,7 @@ public final class EventDataBatch {
this.events = new LinkedList<>();
this.sizeInBytes = (maxMessageSize / 65536) * 1024; // reserve 1KB for every 64KB
this.eventBytes = new byte[maxMessageSize];
- this.tracerProvider = tracerProvider;
- this.entityPath = entityPath;
- this.hostname = hostname;
+ this.tracer = instrumentation.getTracer();
}
/**
@@ -114,11 +99,12 @@ public boolean tryAdd(final EventData eventData) {
if (eventData == null) {
throw LOGGER.logExceptionAsWarning(new NullPointerException("eventData cannot be null"));
}
- EventData event = tracerProvider.isEnabled() ? traceMessageSpan(eventData) : eventData;
+
+ tracer.reportMessageSpan(eventData, eventData.getContext());
final int size;
try {
- size = getSize(event, events.isEmpty());
+ size = getSize(eventData, events.isEmpty());
} catch (BufferOverflowException exception) {
throw LOGGER.logExceptionAsWarning(new AmqpException(false, AmqpErrorCondition.LINK_PAYLOAD_SIZE_EXCEEDED,
String.format(Locale.US, "Size of the payload exceeded maximum message size: %s kb",
@@ -126,52 +112,15 @@ public boolean tryAdd(final EventData eventData) {
contextProvider.getErrorContext()));
}
-
if (this.sizeInBytes + size > this.maxMessageSize) {
return false;
}
this.sizeInBytes += size;
-
-
- this.events.add(event);
+ this.events.add(eventData);
return true;
}
- /**
- * Method to start and end a "Azure.EventHubs.message" span and add the "DiagnosticId" as a property of the message.
- *
- * @param eventData The Event to add tracing span for.
- * @return the updated event data object.
- */
- private EventData traceMessageSpan(EventData eventData) {
- Optional