diff --git a/libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/BotTelemetryClientImpl.java b/libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/ApplicationInsightsBotTelemetryClient.java similarity index 60% rename from libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/BotTelemetryClientImpl.java rename to libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/ApplicationInsightsBotTelemetryClient.java index 5a574164b..6434a7754 100644 --- a/libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/BotTelemetryClientImpl.java +++ b/libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/ApplicationInsightsBotTelemetryClient.java @@ -1,247 +1,264 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.bot.applicationinsights; - -import com.microsoft.applicationinsights.TelemetryClient; -import com.microsoft.applicationinsights.telemetry.EventTelemetry; -import com.microsoft.applicationinsights.telemetry.ExceptionTelemetry; -import com.microsoft.applicationinsights.telemetry.PageViewTelemetry; -import com.microsoft.applicationinsights.telemetry.RemoteDependencyTelemetry; -import com.microsoft.applicationinsights.telemetry.SeverityLevel; -import com.microsoft.applicationinsights.telemetry.TraceTelemetry; -import com.microsoft.bot.builder.BotTelemetryClient; -import com.microsoft.bot.builder.Severity; - -import java.time.Duration; -import java.time.OffsetDateTime; -import java.util.Date; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * A logging client for bot telemetry. - */ -public class BotTelemetryClientImpl implements BotTelemetryClient { - - private final TelemetryClient telemetryClient; - - /** - * Initializes a new instance of the {@link BotTelemetryClient}. - * - * @param withTelemetryClient The telemetry client to forward bot events to. - */ - public BotTelemetryClientImpl(TelemetryClient withTelemetryClient) { - if (withTelemetryClient == null) { - throw new IllegalArgumentException("withTelemetry should be provided"); - } - this.telemetryClient = withTelemetryClient; - } - - /** - * Send information about availability of an application. - * - * @param name Availability test name. - * @param timeStamp The time when the availability was captured. - * @param duration The time taken for the availability test to run. - * @param runLocation Name of the location the availability test was run from. - * @param success True if the availability test ran successfully. - * @param message Error message on availability test run failure. - * @param properties Named string values you can use to classify and search for this availability telemetry. - * @param metrics Additional values associated with this availability telemetry. - */ - @SuppressWarnings("checkstyle:ParameterNumber") - @Override - public void trackAvailability(String name, - OffsetDateTime timeStamp, - Duration duration, - String runLocation, - boolean success, - String message, - Map properties, - Map metrics) { - com.microsoft.applicationinsights.telemetry.Duration durationTelemetry = - new com.microsoft.applicationinsights.telemetry.Duration(duration.toNanos()); - ConcurrentMap concurrentProperties = new ConcurrentHashMap<>(properties); - ConcurrentMap concurrentMetrics = new ConcurrentHashMap<>(metrics); - AvailabilityTelemetry telemetry = new AvailabilityTelemetry( - name, - durationTelemetry, - runLocation, - message, - success, - concurrentMetrics, - concurrentProperties); - if (properties != null) { - for (Map.Entry pair: properties.entrySet()) { - telemetry.getProperties().put(pair.getKey(), pair.getValue()); - } - } - - if (metrics != null) { - for (Map.Entry pair: metrics.entrySet()) { - telemetry.getMetrics().put(pair.getKey(), pair.getValue()); - } - } - - /** - * This should be telemetryClient.trackAvailability(telemetry). - * However, it is not present in TelemetryClient class - */ - telemetryClient.track(telemetry); - } - - /** - * Send information about an external dependency (outgoing call) in the application. - * - * @param dependencyTypeName Name of the command initiated with this dependency call. Low cardinality value. - * Examples are SQL, Azure table, and HTTP. - * @param target External dependency target. - * @param dependencyName Name of the command initiated with this dependency call. Low cardinality value. - * Examples are stored procedure name and URL path template. - * @param data Command initiated by this dependency call. Examples are SQL statement and HTTP - * URL's with all query parameters. - * @param startTime The time when the dependency was called. - * @param duration The time taken by the external dependency to handle the call. - * @param resultCode Result code of dependency call execution. - * @param success True if the dependency call was handled successfully. - */ - @SuppressWarnings("checkstyle:ParameterNumber") - @Override - public void trackDependency(String dependencyTypeName, - String target, - String dependencyName, - String data, - OffsetDateTime startTime, - Duration duration, - String resultCode, - boolean success) { - com.microsoft.applicationinsights.telemetry.Duration durationTelemetry = - new com.microsoft.applicationinsights.telemetry.Duration(duration.toNanos()); - - RemoteDependencyTelemetry telemetry = - new RemoteDependencyTelemetry(dependencyName, data, durationTelemetry, success); - - telemetry.setType(dependencyTypeName); - telemetry.setTarget(target); - telemetry.setTimestamp(new Date(startTime.toInstant().toEpochMilli())); - telemetry.setResultCode(resultCode); - - telemetryClient.trackDependency(telemetry); - } - - /** - * Logs custom events with extensible named fields. - * - * @param eventName A name for the event. - * @param properties Named string values you can use to search and classify events. - * @param metrics Measurements associated with this event. - */ - @Override - public void trackEvent(String eventName, Map properties, Map metrics) { - EventTelemetry telemetry = new EventTelemetry(eventName); - if (properties != null) { - for (Map.Entry pair: properties.entrySet()) { - telemetry.getProperties().put(pair.getKey(), pair.getValue()); - } - } - - if (metrics != null) { - for (Map.Entry pair: metrics.entrySet()) { - telemetry.getMetrics().put(pair.getKey(), pair.getValue()); - } - } - - telemetryClient.trackEvent(telemetry); - } - - /** - * Logs a system exception. - * - * @param exception The exception to log. - * @param properties Named string values you can use to classify and search for this exception. - * @param metrics Additional values associated with this exception - */ - @Override - public void trackException(Exception exception, Map properties, Map metrics) { - ExceptionTelemetry telemetry = new ExceptionTelemetry(exception); - if (properties != null) { - for (Map.Entry pair: properties.entrySet()) { - telemetry.getProperties().put(pair.getKey(), pair.getValue()); - } - } - - if (metrics != null) { - for (Map.Entry pair: metrics.entrySet()) { - telemetry.getMetrics().put(pair.getKey(), pair.getValue()); - } - } - - telemetryClient.trackException(telemetry); - } - - /** - * Send a trace message. - * - * @param message Message to display. - * @param severityLevel Trace severity level {@link Severity}. - * @param properties Named string values you can use to search and classify events. - */ - @Override - public void trackTrace(String message, Severity severityLevel, Map properties) { - TraceTelemetry telemetry = new TraceTelemetry(message); - telemetry.setSeverityLevel(SeverityLevel.values()[severityLevel.ordinal()]); - - if (properties != null) { - for (Map.Entry pair: properties.entrySet()) { - telemetry.getProperties().put(pair.getKey(), pair.getValue()); - } - } - - telemetryClient.trackTrace(telemetry); - } - - /** - * We implemented this method calling the tracePageView method from {@link BotTelemetryClientImpl} as the - * IBotPageViewTelemetryClient has not been implemented. - * {@inheritDoc} - */ - @Override - public void trackDialogView(String dialogName, Map properties, Map metrics) { - trackPageView(dialogName, properties, metrics); - } - - /** - * Logs a dialog entry / as an Application Insights page view. - * - * @param dialogName The name of the dialog to log the entry / start for. - * @param properties Named string values you can use to search and classify events. - * @param metrics Measurements associated with this event. - */ - public void trackPageView(String dialogName, Map properties, Map metrics) { - PageViewTelemetry telemetry = new PageViewTelemetry(dialogName); - - if (properties != null) { - for (Map.Entry pair: properties.entrySet()) { - telemetry.getProperties().put(pair.getKey(), pair.getValue()); - } - } - - if (metrics != null) { - for (Map.Entry pair: metrics.entrySet()) { - telemetry.getMetrics().put(pair.getKey(), pair.getValue()); - } - } - - telemetryClient.trackPageView(telemetry); - } - - /** - * Flushes the in-memory buffer and any metrics being pre-aggregated. - */ - @Override - public void flush() { - telemetryClient.flush(); - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.bot.applicationinsights; + +import com.microsoft.applicationinsights.TelemetryClient; +import com.microsoft.applicationinsights.telemetry.EventTelemetry; +import com.microsoft.applicationinsights.telemetry.ExceptionTelemetry; +import com.microsoft.applicationinsights.telemetry.PageViewTelemetry; +import com.microsoft.applicationinsights.telemetry.RemoteDependencyTelemetry; +import com.microsoft.applicationinsights.telemetry.SeverityLevel; +import com.microsoft.applicationinsights.telemetry.TraceTelemetry; +import com.microsoft.bot.builder.BotTelemetryClient; +import com.microsoft.bot.builder.Severity; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * A logging client for bot telemetry. + */ +public class ApplicationInsightsBotTelemetryClient implements BotTelemetryClient { + + private final TelemetryClient telemetryClient; + + /** + * Initializes a new instance of the {@link BotTelemetryClient}. + * + * @param withTelemetryClient The telemetry client to forward bot events to. + */ + public ApplicationInsightsBotTelemetryClient(TelemetryClient withTelemetryClient) { + if (withTelemetryClient == null) { + throw new IllegalArgumentException("withTelemetry should be provided"); + } + this.telemetryClient = withTelemetryClient; + } + + /** + * Send information about availability of an application. + * + * @param name Availability test name. + * @param timeStamp The time when the availability was captured. + * @param duration The time taken for the availability test to run. + * @param runLocation Name of the location the availability test was run from. + * @param success True if the availability test ran successfully. + * @param message Error message on availability test run failure. + * @param properties Named string values you can use to classify and search for + * this availability telemetry. + * @param metrics Additional values associated with this availability + * telemetry. + */ + @SuppressWarnings("checkstyle:ParameterNumber") + @Override + public void trackAvailability( + String name, + OffsetDateTime timeStamp, + Duration duration, + String runLocation, + boolean success, + String message, + Map properties, + Map metrics + ) { + com.microsoft.applicationinsights.telemetry.Duration durationTelemetry = + new com.microsoft.applicationinsights.telemetry.Duration(duration.toNanos()); + ConcurrentMap concurrentProperties = new ConcurrentHashMap<>(properties); + ConcurrentMap concurrentMetrics = new ConcurrentHashMap<>(metrics); + AvailabilityTelemetry telemetry = new AvailabilityTelemetry( + name, + durationTelemetry, + runLocation, + message, + success, + concurrentMetrics, + concurrentProperties + ); + if (properties != null) { + for (Map.Entry pair : properties.entrySet()) { + telemetry.getProperties().put(pair.getKey(), pair.getValue()); + } + } + + if (metrics != null) { + for (Map.Entry pair : metrics.entrySet()) { + telemetry.getMetrics().put(pair.getKey(), pair.getValue()); + } + } + + /** + * This should be telemetryClient.trackAvailability(telemetry). However, it is + * not present in TelemetryClient class + */ + telemetryClient.track(telemetry); + } + + /** + * Send information about an external dependency (outgoing call) in the + * application. + * + * @param dependencyTypeName Name of the command initiated with this dependency + * call. Low cardinality value. Examples are SQL, + * Azure table, and HTTP. + * @param target External dependency target. + * @param dependencyName Name of the command initiated with this dependency + * call. Low cardinality value. Examples are stored + * procedure name and URL path template. + * @param data Command initiated by this dependency call. Examples + * are SQL statement and HTTP URL's with all query + * parameters. + * @param startTime The time when the dependency was called. + * @param duration The time taken by the external dependency to handle + * the call. + * @param resultCode Result code of dependency call execution. + * @param success True if the dependency call was handled + * successfully. + */ + @SuppressWarnings("checkstyle:ParameterNumber") + @Override + public void trackDependency( + String dependencyTypeName, + String target, + String dependencyName, + String data, + OffsetDateTime startTime, + Duration duration, + String resultCode, + boolean success + ) { + com.microsoft.applicationinsights.telemetry.Duration durationTelemetry = + new com.microsoft.applicationinsights.telemetry.Duration(duration.toNanos()); + + RemoteDependencyTelemetry telemetry = + new RemoteDependencyTelemetry(dependencyName, data, durationTelemetry, success); + + telemetry.setType(dependencyTypeName); + telemetry.setTarget(target); + telemetry.setTimestamp(new Date(startTime.toInstant().toEpochMilli())); + telemetry.setResultCode(resultCode); + + telemetryClient.trackDependency(telemetry); + } + + /** + * Logs custom events with extensible named fields. + * + * @param eventName A name for the event. + * @param properties Named string values you can use to search and classify + * events. + * @param metrics Measurements associated with this event. + */ + @Override + public void trackEvent(String eventName, Map properties, Map metrics) { + EventTelemetry telemetry = new EventTelemetry(eventName); + if (properties != null) { + for (Map.Entry pair : properties.entrySet()) { + telemetry.getProperties().put(pair.getKey(), pair.getValue()); + } + } + + if (metrics != null) { + for (Map.Entry pair : metrics.entrySet()) { + telemetry.getMetrics().put(pair.getKey(), pair.getValue()); + } + } + + telemetryClient.trackEvent(telemetry); + } + + /** + * Logs a system exception. + * + * @param exception The exception to log. + * @param properties Named string values you can use to classify and search for + * this exception. + * @param metrics Additional values associated with this exception + */ + @Override + public void trackException(Exception exception, Map properties, Map metrics) { + ExceptionTelemetry telemetry = new ExceptionTelemetry(exception); + if (properties != null) { + for (Map.Entry pair : properties.entrySet()) { + telemetry.getProperties().put(pair.getKey(), pair.getValue()); + } + } + + if (metrics != null) { + for (Map.Entry pair : metrics.entrySet()) { + telemetry.getMetrics().put(pair.getKey(), pair.getValue()); + } + } + + telemetryClient.trackException(telemetry); + } + + /** + * Send a trace message. + * + * @param message Message to display. + * @param severityLevel Trace severity level {@link Severity}. + * @param properties Named string values you can use to search and classify + * events. + */ + @Override + public void trackTrace(String message, Severity severityLevel, Map properties) { + TraceTelemetry telemetry = new TraceTelemetry(message); + telemetry.setSeverityLevel(SeverityLevel.values()[severityLevel.ordinal()]); + + if (properties != null) { + for (Map.Entry pair : properties.entrySet()) { + telemetry.getProperties().put(pair.getKey(), pair.getValue()); + } + } + + telemetryClient.trackTrace(telemetry); + } + + /** + * We implemented this method calling the tracePageView method from + * {@link ApplicationInsightsBotTelemetryClient} as the + * IBotPageViewTelemetryClient has not been implemented. {@inheritDoc} + */ + @Override + public void trackDialogView(String dialogName, Map properties, Map metrics) { + trackPageView(dialogName, properties, metrics); + } + + /** + * Logs a dialog entry / as an Application Insights page view. + * + * @param dialogName The name of the dialog to log the entry / start for. + * @param properties Named string values you can use to search and classify + * events. + * @param metrics Measurements associated with this event. + */ + public void trackPageView(String dialogName, Map properties, Map metrics) { + PageViewTelemetry telemetry = new PageViewTelemetry(dialogName); + + if (properties != null) { + for (Map.Entry pair : properties.entrySet()) { + telemetry.getProperties().put(pair.getKey(), pair.getValue()); + } + } + + if (metrics != null) { + for (Map.Entry pair : metrics.entrySet()) { + telemetry.getMetrics().put(pair.getKey(), pair.getValue()); + } + } + + telemetryClient.trackPageView(telemetry); + } + + /** + * Flushes the in-memory buffer and any metrics being pre-aggregated. + */ + @Override + public void flush() { + telemetryClient.flush(); + } +} diff --git a/libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/AvailabilityTelemetry.java b/libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/AvailabilityTelemetry.java index 80911aa58..3197840a3 100644 --- a/libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/AvailabilityTelemetry.java +++ b/libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/AvailabilityTelemetry.java @@ -12,8 +12,9 @@ import java.util.concurrent.ConcurrentMap; /** - * We took this class from https://github.com/microsoft/ApplicationInsights-Java/issues/1099 - * as this is not already migrated in ApplicationInsights-Java library. + * We took this class from + * https://github.com/microsoft/ApplicationInsights-Java/issues/1099 as this is + * not already migrated in ApplicationInsights-Java library. */ public final class AvailabilityTelemetry extends BaseSampleSourceTelemetry { private Double samplingPercentage; @@ -23,7 +24,6 @@ public final class AvailabilityTelemetry extends BaseSampleSourceTelemetry measurements, - ConcurrentMap properties) { + public AvailabilityTelemetry( + String name, + Duration duration, + String runLocation, + String message, + boolean success, + ConcurrentMap measurements, + ConcurrentMap properties + ) { this.data = new AvailabilityData(); @@ -70,9 +77,9 @@ public AvailabilityTelemetry(String name, Duration duration, String runLocation, setSuccess(success); } - /** * Gets the ver value from the data object. + * * @return The ver value. */ @Override @@ -82,6 +89,7 @@ public int getVer() { /** * Gets a map of application-defined request metrics. + * * @return The map of metrics */ public ConcurrentMap getMetrics() { @@ -89,7 +97,9 @@ public ConcurrentMap getMetrics() { } /** - * Sets the StartTime. Uses the default behavior and sets the property on the 'data' start time. + * Sets the StartTime. Uses the default behavior and sets the property on the + * 'data' start time. + * * @param timestamp The timestamp as Date. */ @Override @@ -103,6 +113,7 @@ public void setTimestamp(Date timestamp) { /** * Gets or human-readable name of the requested page. + * * @return A human-readable name. */ public String getName() { @@ -111,6 +122,7 @@ public String getName() { /** * Sets or human-readable name of the requested page. + * * @param name A human-readable name. */ public void setName(String name) { @@ -119,6 +131,7 @@ public void setName(String name) { /** * Gets or human-readable name of the run location. + * * @return A human-readable name. */ public String getRunLocation() { @@ -127,6 +140,7 @@ public String getRunLocation() { /** * Sets or human-readable name of the run location. + * * @param runLocation A human-readable name */ public void setRunLocation(String runLocation) { @@ -135,6 +149,7 @@ public void setRunLocation(String runLocation) { /** * Gets the unique identifier of the request. + * * @return Unique identifier. */ public String getId() { @@ -143,6 +158,7 @@ public String getId() { /** * Sets the unique identifier of the request. + * * @param id Unique identifier. */ public void setId(String id) { @@ -151,6 +167,7 @@ public void setId(String id) { /** * Gets a value indicating whether application handled the request successfully. + * * @return Success indication. */ public boolean isSuccess() { @@ -159,6 +176,7 @@ public boolean isSuccess() { /** * Sets a value indicating whether application handled the request successfully. + * * @param success Success indication. */ public void setSuccess(boolean success) { @@ -167,6 +185,7 @@ public void setSuccess(boolean success) { /** * Gets the amount of time it took the application to handle the request. + * * @return Amount of time in milliseconds. */ public Duration getDuration() { @@ -175,7 +194,9 @@ public Duration getDuration() { /** * Sets the amount of time it took the application to handle the request. - * @param duration Amount of time in captured in a {@link com.microsoft.applicationinsights.telemetry.Duration}. + * + * @param duration Amount of time in captured in a + * {@link com.microsoft.applicationinsights.telemetry.Duration}. */ public void setDuration(Duration duration) { data.setDuration(duration); @@ -214,4 +235,3 @@ public String getBaseTypeName() { return BASE_TYPE; } } - diff --git a/libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/core/TelemetryInitializerMiddleware.java b/libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/core/TelemetryInitializerMiddleware.java index 4126e9369..8bf4377be 100644 --- a/libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/core/TelemetryInitializerMiddleware.java +++ b/libraries/bot-applicationinsights/src/main/java/com/microsoft/bot/applicationinsights/core/TelemetryInitializerMiddleware.java @@ -27,11 +27,15 @@ public class TelemetryInitializerMiddleware implements Middleware { /** * Initializes a new instance of the {@link TelemetryInitializerMiddleware}. + * * @param withTelemetryLoggerMiddleware The TelemetryLoggerMiddleware to use. - * @param withLogActivityTelemetry Boolean determining if you want to log telemetry activity + * @param withLogActivityTelemetry Boolean determining if you want to log + * telemetry activity */ - public TelemetryInitializerMiddleware(TelemetryLoggerMiddleware withTelemetryLoggerMiddleware, - Boolean withLogActivityTelemetry) { + public TelemetryInitializerMiddleware( + TelemetryLoggerMiddleware withTelemetryLoggerMiddleware, + Boolean withLogActivityTelemetry + ) { telemetryLoggerMiddleware = withTelemetryLoggerMiddleware; if (withLogActivityTelemetry == null) { withLogActivityTelemetry = true; @@ -40,9 +44,11 @@ public TelemetryInitializerMiddleware(TelemetryLoggerMiddleware withTelemetryLog } /** - * Stores the incoming activity as JSON in the items collection on the HttpContext. + * Stores the incoming activity as JSON in the items collection on the + * HttpContext. + * * @param context The incoming TurnContext - * @param next Delegate to run next on + * @param next Delegate to run next on * @return Returns a CompletableFuture with Void value */ public CompletableFuture onTurn(TurnContext context, NextDelegate next) { @@ -71,4 +77,3 @@ public CompletableFuture onTurn(TurnContext context, NextDelegate next) { } } } - diff --git a/libraries/bot-applicationinsights/src/test/java/com/microsoft/bot/applicationinsights/BotTelemetryClientTests.java b/libraries/bot-applicationinsights/src/test/java/com/microsoft/bot/applicationinsights/BotTelemetryClientTests.java index 5ae1436a7..855f139f9 100644 --- a/libraries/bot-applicationinsights/src/test/java/com/microsoft/bot/applicationinsights/BotTelemetryClientTests.java +++ b/libraries/bot-applicationinsights/src/test/java/com/microsoft/bot/applicationinsights/BotTelemetryClientTests.java @@ -38,13 +38,13 @@ public void initialize() { telemetryConfiguration.setChannel(mockTelemetryChannel); TelemetryClient telemetryClient = new TelemetryClient(telemetryConfiguration); - botTelemetryClient = new BotTelemetryClientImpl(telemetryClient); + botTelemetryClient = new ApplicationInsightsBotTelemetryClient(telemetryClient); } @Test public void nullTelemetryClientThrows() { Assert.assertThrows(IllegalArgumentException.class, () -> { - new BotTelemetryClientImpl(null); + new ApplicationInsightsBotTelemetryClient(null); }); } @@ -52,7 +52,7 @@ public void nullTelemetryClientThrows() { public void nonNullTelemetryClientSucceeds() { TelemetryClient telemetryClient = new TelemetryClient(); - BotTelemetryClient botTelemetryClient = new BotTelemetryClientImpl(telemetryClient); + BotTelemetryClient botTelemetryClient = new ApplicationInsightsBotTelemetryClient(telemetryClient); } @Test diff --git a/libraries/bot-applicationinsights/src/test/java/com/microsoft/bot/applicationinsights/MyBotTelemetryClient.java b/libraries/bot-applicationinsights/src/test/java/com/microsoft/bot/applicationinsights/MyBotTelemetryClient.java index 5558ca0d0..9ccf38495 100644 --- a/libraries/bot-applicationinsights/src/test/java/com/microsoft/bot/applicationinsights/MyBotTelemetryClient.java +++ b/libraries/bot-applicationinsights/src/test/java/com/microsoft/bot/applicationinsights/MyBotTelemetryClient.java @@ -10,7 +10,7 @@ import java.time.OffsetDateTime; import java.util.Map; -public class MyBotTelemetryClient extends BotTelemetryClientImpl { +public class MyBotTelemetryClient extends ApplicationInsightsBotTelemetryClient { public MyBotTelemetryClient(TelemetryClient telemetryClient) { super(telemetryClient); } diff --git a/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/CosmosDbKeyEscape.java b/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/CosmosDbKeyEscape.java index 0c54444be..d952ed901 100644 --- a/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/CosmosDbKeyEscape.java +++ b/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/CosmosDbKeyEscape.java @@ -48,8 +48,8 @@ private CosmosDbKeyEscape() { * means a key of "?test?" would be escaped as "*3ftest*3f". */ private static final Map ILLEGAL_KEY_CHARACTER_REPLACEMENT_MAP = Arrays - .stream(ArrayUtils.toObject(ILLEGAL_KEYS)) - .collect(Collectors.toMap(c -> c, c -> "*" + String.format("%02x", (int) c))); + .stream(ArrayUtils.toObject(ILLEGAL_KEYS)) + .collect(Collectors.toMap(c -> c, c -> "*" + String.format("%02x", (int) c))); /** * Converts the key into a DocumentID that can be used safely with Cosmos DB. @@ -94,8 +94,8 @@ public static String escapeKey(String key, String suffix, Boolean compatibilityM // Allocate a builder that assumes that all remaining characters might be // replaced // to avoid any extra allocations - StringBuilder sanitizedKeyBuilder = new StringBuilder( - key.length() + ((key.length() - firstIllegalCharIndex) * ESCAPE_LENGTH)); + StringBuilder sanitizedKeyBuilder = + new StringBuilder(key.length() + ((key.length() - firstIllegalCharIndex) * ESCAPE_LENGTH)); // Add all good characters up to the first bad character to the builder first for (Integer index = 0; index < firstIllegalCharIndex; index++) { diff --git a/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/CosmosDbPartitionedStorage.java b/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/CosmosDbPartitionedStorage.java index 3a9c32ee1..25a145113 100644 --- a/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/CosmosDbPartitionedStorage.java +++ b/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/CosmosDbPartitionedStorage.java @@ -85,7 +85,8 @@ public CosmosDbPartitionedStorage(CosmosDbPartitionedStorageOptions withCosmosDb if (StringUtils.isNotBlank(withCosmosDbStorageOptions.getKeySuffix())) { if (withCosmosDbStorageOptions.getCompatibilityMode()) { throw new IllegalArgumentException( - "CompatibilityMode cannot be 'true' while using a KeySuffix: withCosmosDbStorageOptions"); + "CompatibilityMode cannot be 'true' while using a KeySuffix: withCosmosDbStorageOptions" + ); } // In order to reduce key complexity, we do not allow invalid characters in a @@ -93,18 +94,28 @@ public CosmosDbPartitionedStorage(CosmosDbPartitionedStorageOptions withCosmosDb // If the KeySuffix has invalid characters, the EscapeKey will not match String suffixEscaped = CosmosDbKeyEscape.escapeKey(withCosmosDbStorageOptions.getKeySuffix()); if (!withCosmosDbStorageOptions.getKeySuffix().equals(suffixEscaped)) { - throw new IllegalArgumentException(String.format("Cannot use invalid Row Key characters: %s %s", - withCosmosDbStorageOptions.getKeySuffix(), "withCosmosDbStorageOptions")); + throw new IllegalArgumentException( + String.format( + "Cannot use invalid Row Key characters: %s %s", + withCosmosDbStorageOptions.getKeySuffix(), + "withCosmosDbStorageOptions" + ) + ); } } cosmosDbStorageOptions = withCosmosDbStorageOptions; objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .findAndRegisterModules().enableDefaultTyping(); - - client = new DocumentClient(cosmosDbStorageOptions.getCosmosDbEndpoint(), cosmosDbStorageOptions.getAuthKey(), - cosmosDbStorageOptions.getConnectionPolicy(), cosmosDbStorageOptions.getConsistencyLevel()); + .findAndRegisterModules() + .enableDefaultTyping(); + + client = new DocumentClient( + cosmosDbStorageOptions.getCosmosDbEndpoint(), + cosmosDbStorageOptions.getAuthKey(), + cosmosDbStorageOptions.getConnectionPolicy(), + cosmosDbStorageOptions.getConsistencyLevel() + ); } /** @@ -128,8 +139,15 @@ public CompletableFuture> read(String[] keys) { // Issue all of the reads at once List> documentFutures = new ArrayList<>(); for (String key : keys) { - documentFutures.add(getDocumentById(CosmosDbKeyEscape.escapeKey(key, - cosmosDbStorageOptions.getKeySuffix(), cosmosDbStorageOptions.getCompatibilityMode()))); + documentFutures.add( + getDocumentById( + CosmosDbKeyEscape.escapeKey( + key, + cosmosDbStorageOptions.getKeySuffix(), + cosmosDbStorageOptions.getCompatibilityMode() + ) + ) + ); } // Map each returned Document to it's original value. @@ -190,8 +208,13 @@ public CompletableFuture write(Map changes) { DocumentStoreItem documentChange = new DocumentStoreItem() { { - setId(CosmosDbKeyEscape.escapeKey(change.getKey(), cosmosDbStorageOptions.getKeySuffix(), - cosmosDbStorageOptions.getCompatibilityMode())); + setId( + CosmosDbKeyEscape.escapeKey( + change.getKey(), + cosmosDbStorageOptions.getKeySuffix(), + cosmosDbStorageOptions.getCompatibilityMode() + ) + ); setReadId(change.getKey()); setDocument(node.toString()); setType(change.getValue().getClass().getTypeName()); @@ -243,8 +266,8 @@ public CompletableFuture delete(String[] keys) { // issue the deletes in parallel return getCollection().thenCompose(collection -> Arrays.stream(keys).map(key -> { - String escapedKey = CosmosDbKeyEscape.escapeKey(key, cosmosDbStorageOptions.getKeySuffix(), - cosmosDbStorageOptions.getCompatibilityMode()); + String escapedKey = CosmosDbKeyEscape + .escapeKey(key, cosmosDbStorageOptions.getKeySuffix(), cosmosDbStorageOptions.getCompatibilityMode()); return getDocumentById(escapedKey).thenApplyAsync(document -> { if (document != null) { try { @@ -266,10 +289,10 @@ public CompletableFuture delete(String[] keys) { private Database getDatabase() { if (databaseCache == null) { // Get the database if it exists - List databaseList = client - .queryDatabases("SELECT * FROM root r WHERE r.id='" + cosmosDbStorageOptions.getDatabaseId() + "'", - null) - .getQueryIterable().toList(); + List databaseList = client.queryDatabases( + "SELECT * FROM root r WHERE r.id='" + cosmosDbStorageOptions.getDatabaseId() + "'", + null + ).getQueryIterable().toList(); if (databaseList.size() > 0) { // Cache the database object so we won't have to query for it @@ -306,9 +329,11 @@ private CompletableFuture getCollection() { return CompletableFuture.supplyAsync(() -> { // Get the collection if it exists. - List collectionList = client.queryCollections(getDatabase().getSelfLink(), - "SELECT * FROM root r WHERE r.id='" + cosmosDbStorageOptions.getContainerId() + "'", null) - .getQueryIterable().toList(); + List collectionList = client.queryCollections( + getDatabase().getSelfLink(), + "SELECT * FROM root r WHERE r.id='" + cosmosDbStorageOptions.getContainerId() + "'", + null + ).getQueryIterable().toList(); if (collectionList.size() > 0) { // Cache the collection object so we won't have to query for it @@ -331,8 +356,8 @@ private CompletableFuture getCollection() { }; collectionCache = client - .createCollection(getDatabase().getSelfLink(), collectionDefinition, options) - .getResource(); + .createCollection(getDatabase().getSelfLink(), collectionDefinition, options) + .getResource(); } catch (DocumentClientException e) { // able to query or create the collection. // Verify your connection, endpoint, and key. @@ -350,8 +375,9 @@ private CompletableFuture getDocumentById(String id) { return getCollection().thenApplyAsync(collection -> { // Retrieve the document using the DocumentClient. List documentList = client - .queryDocuments(collection.getSelfLink(), "SELECT * FROM root r WHERE r.id='" + id + "'", null) - .getQueryIterable().toList(); + .queryDocuments(collection.getSelfLink(), "SELECT * FROM root r WHERE r.id='" + id + "'", null) + .getQueryIterable() + .toList(); if (documentList.size() > 0) { return documentList.get(0); diff --git a/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/CosmosDbPartitionedStorageOptions.java b/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/CosmosDbPartitionedStorageOptions.java index 196f09a16..f51d2bc4b 100644 --- a/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/CosmosDbPartitionedStorageOptions.java +++ b/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/CosmosDbPartitionedStorageOptions.java @@ -201,6 +201,7 @@ public void setContainerThroughput(Integer withContainerThroughput) { * also allow for using older collections where no PartitionKey was specified. * * Note: CompatibilityMode cannot be 'true' if KeySuffix is used. + * * @return The compatibilityMode */ public Boolean getCompatibilityMode() { diff --git a/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/blobs/BlobsStorage.java b/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/blobs/BlobsStorage.java index 19bda96ba..55d4cc331 100644 --- a/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/blobs/BlobsStorage.java +++ b/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/blobs/BlobsStorage.java @@ -32,13 +32,14 @@ import java.util.concurrent.TimeUnit; /** - * Implements {@link Storage} using Azure Storage Blobs. - * This class uses a single Azure Storage Blob Container. - * Each entity or {@link StoreItem} is serialized into a JSON string and stored in an individual text blob. - * Each blob is named after the store item key, which is encoded so that it conforms a valid blob name. - * an entity is an {@link StoreItem}, the storage object will set the entity's {@link StoreItem} - * property value to the blob's ETag upon read. Afterward, an {@link BlobRequestConditions} with the ETag value - * will be generated during Write. New entities start with a null ETag. + * Implements {@link Storage} using Azure Storage Blobs. This class uses a + * single Azure Storage Blob Container. Each entity or {@link StoreItem} is + * serialized into a JSON string and stored in an individual text blob. Each + * blob is named after the store item key, which is encoded so that it conforms + * a valid blob name. an entity is an {@link StoreItem}, the storage object will + * set the entity's {@link StoreItem} property value to the blob's ETag upon + * read. Afterward, an {@link BlobRequestConditions} with the ETag value will be + * generated during Write. New entities start with a null ETag. */ public class BlobsStorage implements Storage { @@ -50,8 +51,10 @@ public class BlobsStorage implements Storage { /** * Initializes a new instance of the {@link BlobsStorage} class. + * * @param dataConnectionString Azure Storage connection string. - * @param containerName Name of the Blob container where entities will be stored. + * @param containerName Name of the Blob container where entities will be + * stored. */ public BlobsStorage(String dataConnectionString, String containerName) { if (StringUtils.isBlank(dataConnectionString)) { @@ -62,19 +65,18 @@ public BlobsStorage(String dataConnectionString, String containerName) { throw new IllegalArgumentException("containerName is required."); } - objectMapper = new ObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .findAndRegisterModules() .enableDefaultTyping(); - containerClient = new BlobContainerClientBuilder() - .connectionString(dataConnectionString) - .containerName(containerName) - .buildClient(); + containerClient = new BlobContainerClientBuilder().connectionString(dataConnectionString) + .containerName(containerName) + .buildClient(); } /** * Deletes entity blobs from the configured container. + * * @param keys An array of entity keys. * @return A task that represents the work queued to execute. */ @@ -84,7 +86,7 @@ public CompletableFuture delete(String[] keys) { throw new IllegalArgumentException("The 'keys' parameter is required."); } - for (String key: keys) { + for (String key : keys) { String blobName = getBlobName(key); BlobClient blobClient = containerClient.getBlobClient(blobName); if (blobClient.exists()) { @@ -102,6 +104,7 @@ public CompletableFuture delete(String[] keys) { /** * Retrieve entities from the configured blob container. + * * @param keys An array of entity keys. * @return A task that represents the work queued to execute. */ @@ -136,6 +139,7 @@ public CompletableFuture> read(String[] keys) { /** * Stores a new entity in the configured blob container. + * * @param changes The changes to write to storage. * @return A task that represents the work queued to execute. */ @@ -157,28 +161,37 @@ public CompletableFuture write(Map changes) { StoreItem storeItem = newValue instanceof StoreItem ? (StoreItem) newValue : null; // "*" eTag in StoreItem converts to null condition for AccessCondition - boolean isNullOrEmpty = storeItem == null || StringUtils.isBlank(storeItem.getETag()) - || storeItem.getETag().equals("*"); - BlobRequestConditions accessCondition = !isNullOrEmpty - ? new BlobRequestConditions().setIfMatch(storeItem.getETag()) - : null; + boolean isNullOrEmpty = + storeItem == null || StringUtils.isBlank(storeItem.getETag()) || storeItem.getETag().equals("*"); + BlobRequestConditions accessCondition = + !isNullOrEmpty ? new BlobRequestConditions().setIfMatch(storeItem.getETag()) : null; String blobName = getBlobName(keyValuePair.getKey()); BlobClient blobReference = containerClient.getBlobClient(blobName); try { String json = objectMapper.writeValueAsString(newValue); InputStream stream = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)); - //verify the corresponding length - blobReference.uploadWithResponse(stream, stream.available(), - null, null, - null, null, accessCondition, null, Context.NONE); + // verify the corresponding length + blobReference.uploadWithResponse( + stream, + stream.available(), + null, + null, + null, + null, + accessCondition, + null, + Context.NONE + ); } catch (HttpResponseException e) { if (e.getResponse().getStatusCode() == HttpStatus.SC_BAD_REQUEST) { StringBuilder sb = new StringBuilder("An error occurred while trying to write an object. The underlying "); sb.append(BlobErrorCode.INVALID_BLOCK_LIST); - sb.append(" error is commonly caused due to " - + "concurrently uploading an object larger than 128MB in size."); + sb.append( + " error is commonly caused due to " + + "concurrently uploading an object larger than 128MB in size." + ); throw new HttpResponseException(sb.toString(), e.getResponse()); } @@ -210,12 +223,13 @@ private CompletableFuture innerReadBlob(BlobClient blobReference) { while (true) { try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { blobReference.download(outputStream); - String contentString = outputStream.toString(); + String contentString = outputStream.toString(); Object obj; // We are doing this try/catch because we are receiving String or HashMap try { - // We need to deserialize to an Object class since there are contentString which has an Object type + // We need to deserialize to an Object class since there are contentString which + // has an Object type obj = objectMapper.readValue(contentString, Object.class); } catch (MismatchedInputException ex) { // In case of the contentString has the structure of a HashMap, @@ -232,7 +246,8 @@ private CompletableFuture innerReadBlob(BlobClient blobReference) { } catch (HttpResponseException e) { if (e.getResponse().getStatusCode() == HttpStatus.SC_PRECONDITION_FAILED) { // additional retry logic, - // even though this is a read operation blob storage can return 412 if there is contention + // even though this is a read operation blob storage can return 412 if there is + // contention if (i++ < retryTimes) { try { TimeUnit.MILLISECONDS.sleep(millisecondsTimeout); diff --git a/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/blobs/BlobsTranscriptStore.java b/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/blobs/BlobsTranscriptStore.java index ada2b7c32..76b78e837 100644 --- a/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/blobs/BlobsTranscriptStore.java +++ b/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/blobs/BlobsTranscriptStore.java @@ -68,8 +68,10 @@ public class BlobsTranscriptStore implements TranscriptStore { /** * Initializes a new instance of the {@link BlobsTranscriptStore} class. + * * @param dataConnectionString Azure Storage connection string. - * @param containerName Name of the Blob container where entities will be stored. + * @param containerName Name of the Blob container where entities will be + * stored. */ public BlobsTranscriptStore(String dataConnectionString, String containerName) { if (StringUtils.isBlank(dataConnectionString)) { @@ -80,8 +82,7 @@ public BlobsTranscriptStore(String dataConnectionString, String containerName) { throw new IllegalArgumentException("containerName"); } - jsonSerializer = new ObjectMapper() - .setSerializationInclusion(JsonInclude.Include.NON_NULL) + jsonSerializer = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL) .enable(SerializationFeature.INDENT_OUTPUT) .findAndRegisterModules(); @@ -91,6 +92,7 @@ public BlobsTranscriptStore(String dataConnectionString, String containerName) { /** * Log an activity to the transcript. + * * @param activity Activity being logged. * @return A CompletableFuture that represents the work queued to execute. */ @@ -101,8 +103,8 @@ public CompletableFuture logActivity(Activity activity) { case ActivityTypes.MESSAGE_UPDATE: Activity updatedActivity = null; try { - updatedActivity = jsonSerializer - .readValue(jsonSerializer.writeValueAsString(activity), Activity.class); + updatedActivity = + jsonSerializer.readValue(jsonSerializer.writeValueAsString(activity), Activity.class); } catch (IOException ex) { ex.printStackTrace(); } @@ -122,6 +124,7 @@ public CompletableFuture logActivity(Activity activity) { }); return CompletableFuture.completedFuture(null); + case ActivityTypes.MESSAGE_DELETE: innerReadBlob(activity).thenAccept(activityAndBlob -> { if (activityAndBlob != null && activityAndBlob.getLeft() != null) { @@ -147,19 +150,20 @@ public CompletableFuture logActivity(Activity activity) { logActivityToBlobClient(tombstonedActivity, activityAndBlob.getRight(), true) .thenApply(task -> CompletableFuture.completedFuture(null)); - } + } }); return CompletableFuture.completedFuture(null); + default: - this.innerLogActivity(activity) - .thenApply(task -> CompletableFuture.completedFuture(null)); + this.innerLogActivity(activity).thenApply(task -> CompletableFuture.completedFuture(null)); return CompletableFuture.completedFuture(null); } } /** * Get activities for a conversation (Aka the transcript). + * * @param channelId The ID of the channel the conversation is in. * @param conversationId The ID of the conversation. * @param continuationToken The continuation token (if available). @@ -167,9 +171,12 @@ public CompletableFuture logActivity(Activity activity) { * not included. * @return PagedResult of activities. */ - public CompletableFuture> getTranscriptActivities(String channelId, String conversationId, - @Nullable String continuationToken, - OffsetDateTime startDate) { + public CompletableFuture> getTranscriptActivities( + String channelId, + String conversationId, + @Nullable String continuationToken, + OffsetDateTime startDate + ) { if (startDate == null) { startDate = OffsetDateTime.MIN; } @@ -194,11 +201,10 @@ public CompletableFuture> getTranscriptActivities(String c .listBlobsByHierarchy("/", this.getOptionsWithMetadata(prefix), null) .iterableByPage(token); token = null; - for (PagedResponse blobPage: resultSegment) { - for (BlobItem blobItem: blobPage.getValue()) { + for (PagedResponse blobPage : resultSegment) { + for (BlobItem blobItem : blobPage.getValue()) { OffsetDateTime parseDateTime = OffsetDateTime.parse(blobItem.getMetadata().get("Timestamp")); - if (parseDateTime.isAfter(startDate) - || parseDateTime.isEqual(startDate)) { + if (parseDateTime.isAfter(startDate) || parseDateTime.isEqual(startDate)) { if (continuationToken != null) { if (blobItem.getName().equals(continuationToken)) { // we found continuation token @@ -218,14 +224,10 @@ public CompletableFuture> getTranscriptActivities(String c } } while (!StringUtils.isBlank(token) && blobs.size() < pageSize); - pagedResult.setItems(blobs - .stream() - .map(bl -> { - BlobClient blobClient = containerClient.getBlobClient(bl.getName()); - return this.getActivityFromBlobClient(blobClient); - }) - .map(t -> t.join()) - .collect(Collectors.toList())); + pagedResult.setItems(blobs.stream().map(bl -> { + BlobClient blobClient = containerClient.getBlobClient(bl.getName()); + return this.getActivityFromBlobClient(blobClient); + }).map(t -> t.join()).collect(Collectors.toList())); if (pagedResult.getItems().size() == pageSize) { pagedResult.setContinuationToken(blobs.get(blobs.size() - 1).getName()); @@ -236,12 +238,15 @@ public CompletableFuture> getTranscriptActivities(String c /** * List conversations in the channelId. + * * @param channelId The ID of the channel. * @param continuationToken The continuation token (if available). * @return A CompletableFuture that represents the work queued to execute. */ - public CompletableFuture> listTranscripts(String channelId, - @Nullable String continuationToken) { + public CompletableFuture> listTranscripts( + String channelId, + @Nullable String continuationToken + ) { final int pageSize = 20; if (StringUtils.isBlank(channelId)) { @@ -253,16 +258,17 @@ public CompletableFuture> listTranscripts(String cha List conversations = new ArrayList(); do { String prefix = String.format("%s/", sanitizeKey(channelId)); - Iterable> resultSegment = containerClient. - listBlobsByHierarchy("/", this.getOptionsWithMetadata(prefix), null) + Iterable> resultSegment = containerClient + .listBlobsByHierarchy("/", this.getOptionsWithMetadata(prefix), null) .iterableByPage(token); token = null; - for (PagedResponse blobPage: resultSegment) { - for (BlobItem blobItem: blobPage.getValue()) { + for (PagedResponse blobPage : resultSegment) { + for (BlobItem blobItem : blobPage.getValue()) { // Unescape the Id we escaped when we saved it String conversationId = new String(); String lastName = Arrays.stream(blobItem.getName().split("/")) - .reduce((first, second) -> second.length() > 0 ? second : first).get(); + .reduce((first, second) -> second.length() > 0 ? second : first) + .get(); try { conversationId = URLDecoder.decode(lastName, StandardCharsets.UTF_8.name()); } catch (UnsupportedEncodingException ex) { @@ -299,6 +305,7 @@ public CompletableFuture> listTranscripts(String cha /** * Delete a specific conversation and all of it's activities. + * * @param channelId The ID of the channel the conversation is in. * @param conversationId The ID of the conversation to delete. * @return A CompletableFuture that represents the work queued to execute. @@ -316,11 +323,12 @@ public CompletableFuture deleteTranscript(String channelId, String convers do { String prefix = String.format("%s/%s/", sanitizeKey(channelId), sanitizeKey(conversationId)); Iterable> resultSegment = containerClient - .listBlobsByHierarchy("/", this.getOptionsWithMetadata(prefix), null).iterableByPage(token); + .listBlobsByHierarchy("/", this.getOptionsWithMetadata(prefix), null) + .iterableByPage(token); token = null; - for (PagedResponse blobPage: resultSegment) { - for (BlobItem blobItem: blobPage.getValue()) { + for (PagedResponse blobPage : resultSegment) { + for (BlobItem blobItem : blobPage.getValue()) { BlobClient blobClient = containerClient.getBlobClient(blobItem.getName()); if (blobClient.exists()) { try { @@ -345,19 +353,22 @@ private CompletableFuture> innerReadBlob(Activity act try { String token = null; do { - String prefix = String.format("%s/%s/", - sanitizeKey(activity.getChannelId()), sanitizeKey(activity.getConversation().getId())); + String prefix = String.format( + "%s/%s/", + sanitizeKey(activity.getChannelId()), + sanitizeKey(activity.getConversation().getId()) + ); Iterable> resultSegment = containerClient - .listBlobsByHierarchy("/", - this.getOptionsWithMetadata(prefix), null).iterableByPage(token); + .listBlobsByHierarchy("/", this.getOptionsWithMetadata(prefix), null) + .iterableByPage(token); token = null; - for (PagedResponse blobPage: resultSegment) { - for (BlobItem blobItem: blobPage.getValue()) { + for (PagedResponse blobPage : resultSegment) { + for (BlobItem blobItem : blobPage.getValue()) { if (blobItem.getMetadata().get("Id").equals(activity.getId())) { BlobClient blobClient = containerClient.getBlobClient(blobItem.getName()); - return this.getActivityFromBlobClient(blobClient) - .thenApply(blobActivity -> - new Pair(blobActivity, blobClient)); + return this.getActivityFromBlobClient( + blobClient + ).thenApply(blobActivity -> new Pair(blobActivity, blobClient)); } } @@ -370,7 +381,8 @@ private CompletableFuture> innerReadBlob(Activity act } catch (HttpResponseException ex) { if (ex.getResponse().getStatusCode() == HttpStatus.SC_PRECONDITION_FAILED) { // additional retry logic, - // even though this is a read operation blob storage can return 412 if there is contention + // even though this is a read operation blob storage can return 412 if there is + // contention if (i++ < retryTimes) { try { TimeUnit.MILLISECONDS.sleep(milisecondsTimeout); @@ -405,8 +417,11 @@ private CompletableFuture innerLogActivity(Activity activity) { return logActivityToBlobClient(activity, blobClient, null); } - private CompletableFuture logActivityToBlobClient(Activity activity, BlobClient blobClient, - Boolean overwrite) { + private CompletableFuture logActivityToBlobClient( + Activity activity, + BlobClient blobClient, + Boolean overwrite + ) { if (overwrite == null) { overwrite = false; } @@ -440,9 +455,13 @@ private CompletableFuture logActivityToBlobClient(Activity activity, BlobC } private String getBlobName(Activity activity) { - String blobName = String.format("%s/%s/%s-%s.json", - sanitizeKey(activity.getChannelId()), sanitizeKey(activity.getConversation().getId()), - this.formatTicks(activity.getTimestamp()), sanitizeKey(activity.getId())); + String blobName = String.format( + "%s/%s/%s-%s.json", + sanitizeKey(activity.getChannelId()), + sanitizeKey(activity.getConversation().getId()), + this.formatTicks(activity.getTimestamp()), + sanitizeKey(activity.getId()) + ); return blobName; } @@ -459,8 +478,7 @@ private String sanitizeKey(String key) { private BlobContainerClient getContainerClient(String dataConnectionString, String containerName) { containerName = containerName.toLowerCase(); - containerClient = new BlobContainerClientBuilder() - .connectionString(dataConnectionString) + containerClient = new BlobContainerClientBuilder().connectionString(dataConnectionString) .containerName(containerName) .buildClient(); if (!CHECKED_CONTAINERS.contains(containerName)) { @@ -478,12 +496,12 @@ private BlobContainerClient getContainerClient(String dataConnectionString, Stri /** * Formats a timestamp in a way that is consistent with the C# SDK. + * * @param dateTime The dateTime used to get the ticks * @return The String representing the ticks. */ private String formatTicks(OffsetDateTime dateTime) { - final Instant begin = ZonedDateTime.of(1, 1, 1, 0, 0, 0, 0, - ZoneOffset.UTC).toInstant(); + final Instant begin = ZonedDateTime.of(1, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant(); final Instant end = dateTime.toInstant(); long secsDiff = Math.subtractExact(end.getEpochSecond(), begin.getEpochSecond()); long totalHundredNanos = Math.multiplyExact(secsDiff, multipleProductValue); diff --git a/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/queues/AzureQueueStorage.java b/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/queues/AzureQueueStorage.java index b351cc640..e839e7c85 100644 --- a/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/queues/AzureQueueStorage.java +++ b/libraries/bot-azure/src/main/java/com/microsoft/bot/azure/queues/AzureQueueStorage.java @@ -27,8 +27,10 @@ public class AzureQueueStorage extends QueueStorage { /** * Initializes a new instance of the {@link AzureQueueStorage} class. + * * @param queuesStorageConnectionString Azure Storage connection string. - * @param queueName Name of the storage queue where entities will be queued. + * @param queueName Name of the storage queue where entities + * will be queued. */ public AzureQueueStorage(String queuesStorageConnectionString, String queueName) { if (StringUtils.isBlank(queuesStorageConnectionString)) { @@ -39,27 +41,32 @@ public AzureQueueStorage(String queuesStorageConnectionString, String queueName) throw new IllegalArgumentException("queueName is required."); } - queueClient = new QueueClientBuilder() - .connectionString(queuesStorageConnectionString) - .queueName(queueName) - .buildClient(); + queueClient = + new QueueClientBuilder().connectionString(queuesStorageConnectionString).queueName(queueName).buildClient(); } /** - * Queue an Activity to an Azure.Storage.Queues.QueueClient. - * The visibility timeout specifies how long the message should be invisible - * to Dequeue and Peek operations. The message content must be a UTF-8 encoded string that is up to 64KB in size. - * @param activity This is expected to be an {@link Activity} retrieved from a call to - * activity.GetConversationReference().GetContinuationActivity(). - * This enables restarting the conversation using BotAdapter.ContinueConversationAsync. + * Queue an Activity to an Azure.Storage.Queues.QueueClient. The visibility + * timeout specifies how long the message should be invisible to Dequeue and + * Peek operations. The message content must be a UTF-8 encoded string that is + * up to 64KB in size. + * + * @param activity This is expected to be an {@link Activity} retrieved + * from a call to + * activity.GetConversationReference().GetContinuationActivity(). + * This enables restarting the conversation using + * BotAdapter.ContinueConversationAsync. * @param visibilityTimeout Default value of 0. Cannot be larger than 7 days. - * @param timeToLive Specifies the time-to-live interval for the message. - * @return {@link SendMessageResult} as a Json string, from the QueueClient SendMessageAsync operation. + * @param timeToLive Specifies the time-to-live interval for the message. + * @return {@link SendMessageResult} as a Json string, from the QueueClient + * SendMessageAsync operation. */ @Override - public CompletableFuture queueActivity(Activity activity, - @Nullable Duration visibilityTimeout, - @Nullable Duration timeToLive) { + public CompletableFuture queueActivity( + Activity activity, + @Nullable Duration visibilityTimeout, + @Nullable Duration timeToLive + ) { return CompletableFuture.supplyAsync(() -> { if (createQueueIfNotExists) { try { @@ -68,7 +75,8 @@ public CompletableFuture queueActivity(Activity activity, throw new RuntimeException(e); } - // This is an optimization flag to check if the container creation call has been made. + // This is an optimization flag to check if the container creation call has been + // made. // It is okay if this is called more than once. createQueueIfNotExists = false; }