diff --git a/etc/bot-checkstyle.xml b/etc/bot-checkstyle.xml
index 41b3575cb..337417b9e 100644
--- a/etc/bot-checkstyle.xml
+++ b/etc/bot-checkstyle.xml
@@ -159,7 +159,9 @@
-
+
+
+
diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotAdapter.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotAdapter.java
index 2d2006e6b..c9d2f64f7 100644
--- a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotAdapter.java
+++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotAdapter.java
@@ -13,6 +13,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import org.apache.commons.lang3.NotImplementedException;
+import org.apache.commons.lang3.StringUtils;
/**
* Represents a bot adapter that can connect a bot to a service endpoint. This
@@ -194,6 +195,10 @@ protected CompletableFuture runPipeline(
// Call any registered Middleware Components looking for ReceiveActivity()
if (context.getActivity() != null) {
+ if (!StringUtils.isEmpty(context.getActivity().getLocale())) {
+ context.setLocale(context.getActivity().getLocale());
+ }
+
return middlewareSet.receiveActivityWithStatus(context, callback)
.exceptionally(exception -> {
if (onTurnError != null) {
diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotState.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotState.java
index e0261da7c..5c56dfbff 100644
--- a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotState.java
+++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotState.java
@@ -175,7 +175,9 @@ public CompletableFuture saveChanges(TurnContext turnContext, boolean forc
*/
public CompletableFuture clearState(TurnContext turnContext) {
if (turnContext == null) {
- throw new IllegalArgumentException("turnContext cannot be null");
+ return Async.completeExceptionally(new IllegalArgumentException(
+ "TurnContext cannot be null."
+ ));
}
turnContext.getTurnState().replace(contextServiceKey, new CachedBotState());
@@ -190,7 +192,9 @@ public CompletableFuture clearState(TurnContext turnContext) {
*/
public CompletableFuture delete(TurnContext turnContext) {
if (turnContext == null) {
- throw new IllegalArgumentException("turnContext cannot be null");
+ return Async.completeExceptionally(new IllegalArgumentException(
+ "TurnContext cannot be null."
+ ));
}
String storageKey = getStorageKey(turnContext);
@@ -220,6 +224,20 @@ public JsonNode get(TurnContext turnContext) {
return new ObjectMapper().valueToTree(cachedState.state);
}
+ /**
+ * Gets the cached bot state instance that wraps the raw cached data for this BotState from the turn context.
+ *
+ * @param turnContext The context object for this turn.
+ * @return The cached bot state instance.
+ */
+ public CachedBotState getCachedState(TurnContext turnContext) {
+ if (turnContext == null) {
+ throw new IllegalArgumentException("turnContext cannot be null");
+ }
+
+ return turnContext.getTurnState().get(contextServiceKey);
+ }
+
/**
* When overridden in a derived class, gets the key to use when reading and
* writing state to and from storage.
@@ -274,11 +292,15 @@ protected CompletableFuture deletePropertyValue(
String propertyName
) {
if (turnContext == null) {
- throw new IllegalArgumentException("turnContext cannot be null");
+ return Async.completeExceptionally(new IllegalArgumentException(
+ "TurnContext cannot be null."
+ ));
}
if (StringUtils.isEmpty(propertyName)) {
- throw new IllegalArgumentException("propertyName cannot be empty");
+ return Async.completeExceptionally(new IllegalArgumentException(
+ "propertyName cannot be empty"
+ ));
}
CachedBotState cachedState = turnContext.getTurnState().get(contextServiceKey);
@@ -300,11 +322,15 @@ protected CompletableFuture setPropertyValue(
Object value
) {
if (turnContext == null) {
- throw new IllegalArgumentException("turnContext cannot be null");
+ return Async.completeExceptionally(new IllegalArgumentException(
+ "turnContext cannot be null."
+ ));
}
if (StringUtils.isEmpty(propertyName)) {
- throw new IllegalArgumentException("propertyName cannot be empty");
+ return Async.completeExceptionally(new IllegalArgumentException(
+ "propertyName cannot be empty"
+ ));
}
CachedBotState cachedState = turnContext.getTurnState().get(contextServiceKey);
@@ -315,7 +341,7 @@ protected CompletableFuture setPropertyValue(
/**
* Internal cached bot state.
*/
- private static class CachedBotState {
+ public static class CachedBotState {
/**
* In memory cache of BotState properties.
*/
@@ -348,26 +374,46 @@ private static class CachedBotState {
hash = computeHash(withState);
}
- Map getState() {
+ /**
+ * @return The Map of key value pairs which are the state.
+ */
+ public Map getState() {
return state;
}
+ /**
+ * @param withState The key value pairs to set the state with.
+ */
void setState(Map withState) {
state = withState;
}
+ /**
+ * @return The hash value for the state.
+ */
String getHash() {
return hash;
}
+ /**
+ * @param witHashCode Set the hash value.
+ */
void setHash(String witHashCode) {
hash = witHashCode;
}
+ /**
+ *
+ * @return Boolean to tell if the state has changed.
+ */
boolean isChanged() {
return !StringUtils.equals(hash, computeHash(state));
}
+ /**
+ * @param obj The object to compute the hash for.
+ * @return The computed has for the provided object.
+ */
String computeHash(Object obj) {
if (obj == null) {
return "";
diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotTelemetryClient.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotTelemetryClient.java
index 4acf819ab..9b0ace749 100644
--- a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotTelemetryClient.java
+++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotTelemetryClient.java
@@ -153,6 +153,18 @@ void trackException(
*/
void trackTrace(String message, Severity severityLevel, Map properties);
+ /**
+ * Log a DialogView using the TrackPageView method on the IBotTelemetryClient if
+ * IBotPageViewTelemetryClient has been implemented. Alternatively log the information out via
+ * TrackTrace.
+ *
+ * @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.
+ */
+ void trackDialogView(String dialogName, Map properties, Map metrics);
+
/**
* Flushes the in-memory buffer and any metrics being pre-aggregated.
*/
diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/ComponentRegistration.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/ComponentRegistration.java
new file mode 100644
index 000000000..8c808fe95
--- /dev/null
+++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/ComponentRegistration.java
@@ -0,0 +1,34 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.microsoft.bot.builder;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * ComponentRegistration is a signature class for discovering assets from components.
+ */
+@SuppressWarnings("checkstyle:HideUtilityClassConstructor")
+public class ComponentRegistration {
+
+ private static final ConcurrentHashMap, ComponentRegistration> COMPONENTS =
+ new ConcurrentHashMap, ComponentRegistration>();
+
+ /**
+ * Add a component which implements registration methods.
+ *
+ * @param componentRegistration The component to add to the registration.
+ */
+ public static void add(ComponentRegistration componentRegistration) {
+ COMPONENTS.put(componentRegistration.getClass(), componentRegistration);
+ }
+
+ /**
+ * Gets list of all ComponentRegistration objects registered.
+ *
+ * @return A array of ComponentRegistration objects.
+ */
+ public static Iterable getComponents() {
+ return COMPONENTS.values();
+ }
+}
diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/DelegatingTurnContext.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/DelegatingTurnContext.java
index 8256ed509..db0999daa 100644
--- a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/DelegatingTurnContext.java
+++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/DelegatingTurnContext.java
@@ -29,6 +29,24 @@ public DelegatingTurnContext(TurnContext withTurnContext) {
innerTurnContext = withTurnContext;
}
+ /**
+ * Gets the locale on this context object.
+ * @return The string of locale on this context object.
+ */
+ @Override
+ public String getLocale() {
+ return innerTurnContext.getLocale();
+ }
+
+ /**
+ * Set the locale on this context object.
+ * @param withLocale The string of locale on this context object.
+ */
+ @Override
+ public void setLocale(String withLocale) {
+ innerTurnContext.setLocale(withLocale);
+ }
+
/**
* Gets the inner context's activity.
*
diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/NextDelegate.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/NextDelegate.java
index f429207c2..ec89525a6 100644
--- a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/NextDelegate.java
+++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/NextDelegate.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import java.util.concurrent.CompletableFuture;
diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/NullBotTelemetryClient.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/NullBotTelemetryClient.java
index 54f8fb6b4..e45217f1b 100644
--- a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/NullBotTelemetryClient.java
+++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/NullBotTelemetryClient.java
@@ -68,4 +68,9 @@ public void trackTrace(String message, Severity severityLevel, Map properties, Map metrics) {
+
+ }
}
diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/OnTurnErrorHandler.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/OnTurnErrorHandler.java
index 4b5b222c3..3f699e89f 100644
--- a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/OnTurnErrorHandler.java
+++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/OnTurnErrorHandler.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import java.util.concurrent.CompletableFuture;
diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/RegisterClassMiddleware.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/RegisterClassMiddleware.java
new file mode 100644
index 000000000..6d4e7ce30
--- /dev/null
+++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/RegisterClassMiddleware.java
@@ -0,0 +1,74 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.microsoft.bot.builder;
+
+import java.util.concurrent.CompletableFuture;
+
+import com.nimbusds.oauth2.sdk.util.StringUtils;
+
+/**
+ * Middleware for adding an object to or registering a service with the current
+ * turn context.
+ *
+ * @param The typeof service to add.
+ */
+public class RegisterClassMiddleware implements Middleware {
+ private String key;
+
+ /**
+ * Initializes a new instance of the RegisterClassMiddleware class.
+ *
+ * @param service The Service to register.
+ */
+ public RegisterClassMiddleware(T service) {
+ this.service = service;
+ }
+
+ /**
+ * Initializes a new instance of the RegisterClassMiddleware class.
+ *
+ * @param service The Service to register.
+ * @param key optional key for service object in turn state. Default is name
+ * of service.
+ */
+ public RegisterClassMiddleware(T service, String key) {
+ this.service = service;
+ this.key = key;
+ }
+
+ private T service;
+
+ /**
+ * Gets the Service.
+ *
+ * @return The Service.
+ */
+ public T getService() {
+ return service;
+ }
+
+ /**
+ * Sets the Service.
+ *
+ * @param withService The value to set the Service to.
+ */
+ public void setService(T withService) {
+ this.service = withService;
+ }
+
+ @Override
+ /**
+ * Adds the associated object or service to the current turn context.
+ * @param turnContext The context object for this turn.
+ * @param next The delegate to call to continue the bot middleware pipeline.
+ */
+ public CompletableFuture onTurn(TurnContext turnContext, NextDelegate next) {
+ if (!StringUtils.isBlank(key)) {
+ turnContext.getTurnState().add(key, service);
+ } else {
+ turnContext.getTurnState().add(service);
+ }
+ return next.next();
+ }
+}
diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/TurnContext.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/TurnContext.java
index d51ae99be..cea9ebbcf 100644
--- a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/TurnContext.java
+++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/TurnContext.java
@@ -50,11 +50,31 @@ static CompletableFuture traceActivity(
String valueType,
String label
) {
-
return turnContext
.sendActivity(turnContext.getActivity().createTrace(name, value, valueType, label));
}
+ /**
+ * @param turnContext The turnContext.
+ * @param name The name of the activity.
+ * @return A future with the ResourceReponse.
+ */
+ static CompletableFuture traceActivity(TurnContext turnContext, String name) {
+ return traceActivity(turnContext, name, null, null, null);
+ }
+
+ /**
+ * Gets the locale on this context object.
+ * @return The string of locale on this context object.
+ */
+ String getLocale();
+
+ /**
+ * Set the locale on this context object.
+ * @param withLocale The string of locale on this context object.
+ */
+ void setLocale(String withLocale);
+
/**
* Gets the bot adapter that created this context object.
*
diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/TurnContextImpl.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/TurnContextImpl.java
index 050c311a0..2d53e94c3 100644
--- a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/TurnContextImpl.java
+++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/TurnContextImpl.java
@@ -9,6 +9,8 @@
import com.microsoft.bot.schema.ConversationReference;
import com.microsoft.bot.schema.InputHints;
import com.microsoft.bot.schema.ResourceResponse;
+import java.util.Locale;
+import org.apache.commons.lang3.LocaleUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
@@ -62,6 +64,8 @@ public class TurnContextImpl implements TurnContext, AutoCloseable {
*/
private Boolean responded = false;
+ private static final String STATE_TURN_LOCALE = "turn.locale";
+
/**
* Creates a context object.
*
@@ -187,6 +191,32 @@ public boolean getResponded() {
return responded;
}
+ /**
+ * Gets the locale on this context object.
+ * @return The string of locale on this context object.
+ */
+ @Override
+ public String getLocale() {
+ return getTurnState().get(STATE_TURN_LOCALE);
+ }
+
+ /**
+ * Set the locale on this context object.
+ * @param withLocale The string of locale on this context object.
+ */
+ @Override
+ public void setLocale(String withLocale) {
+ if (StringUtils.isEmpty(withLocale)) {
+ getTurnState().remove(STATE_TURN_LOCALE);
+ } else if (
+ LocaleUtils.isAvailableLocale(new Locale.Builder().setLanguageTag(withLocale).build())
+ ) {
+ getTurnState().replace(STATE_TURN_LOCALE, withLocale);
+ } else {
+ getTurnState().replace(STATE_TURN_LOCALE, Locale.ENGLISH.getCountry());
+ }
+ }
+
/**
* Sends a message activity to the sender of the incoming activity.
*
diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/TurnContextStateCollection.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/TurnContextStateCollection.java
index c1f5ff73e..f42e8b5f4 100644
--- a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/TurnContextStateCollection.java
+++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/TurnContextStateCollection.java
@@ -39,21 +39,30 @@ public T get(String key) throws IllegalArgumentException {
}
}
+ /**
+ * Returns the Services stored in the TurnContextStateCollection.
+ * @return the Map of String, Object pairs that contains the names and services for this collection.
+ */
+ public Map getTurnStateServices() {
+ return state;
+ }
+
+
/**
* Get a service by type using its full type name as the key.
*
* @param type The type of service to be retrieved. This will use the value
- * returned by Class.getSimpleName as the key.
+ * returned by Class.getName as the key.
* @param The type of the value.
* @return The service stored under the specified key.
*/
public T get(Class type) {
- return get(type.getSimpleName());
+ return get(type.getName());
}
/**
* Adds a value to the turn's context.
- *
+ *
* @param key The name of the value.
* @param value The value to add.
* @param The type of the value.
@@ -76,7 +85,7 @@ public void add(String key, T value) throws IllegalArgumentException {
}
/**
- * Add a service using its type name ({@link Class#getSimpleName()} as the key.
+ * Add a service using its type name ({@link Class#getName()} as the key.
*
* @param value The service to add.
* @param The type of the value.
@@ -87,12 +96,12 @@ public void add(T value) throws IllegalArgumentException {
throw new IllegalArgumentException("value");
}
- add(value.getClass().getSimpleName(), value);
+ add(value.getClass().getName(), value);
}
/**
* Removes a value.
- *
+ *
* @param key The name of the value to remove.
*/
public void remove(String key) {
@@ -101,7 +110,7 @@ public void remove(String key) {
/**
* Replaces a value.
- *
+ *
* @param key The name of the value to replace.
* @param value The new value.
*/
@@ -110,6 +119,26 @@ public void replace(String key, Object value) {
add(key, value);
}
+ /**
+ * Replaces a value.
+ * @param value The service to add.
+ * @param The type of the value.
+ */
+ public void replace(T value) {
+ String key = value.getClass().getName();
+ replace(key, value);
+ }
+
+ /**
+ * Returns true if this contains a mapping for the specified
+ * key.
+ * @param key The name of the value.
+ * @return True if the key exists.
+ */
+ public boolean containsKey(String key) {
+ return state.containsKey(key);
+ }
+
/**
* Auto call of {@link #close}.
*/
@@ -124,7 +153,7 @@ public void finalize() {
/**
* Close all contained {@link AutoCloseable} values.
- *
+ *
* @throws Exception Exceptions encountered by children during close.
*/
@Override
@@ -138,4 +167,16 @@ public void close() throws Exception {
}
}
}
+
+ /**
+ * Copy the values from another TurnContextStateCollection.
+ * @param other The collection to copy.
+ */
+ public void copy(TurnContextStateCollection other) {
+ if (other != null) {
+ for (String key : other.state.keySet()) {
+ state.put(key, other.state.get(key));
+ }
+ }
+ }
}
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/ActivityHandlerTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/ActivityHandlerTests.java
index 6b6d7590f..4b358b2db 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/ActivityHandlerTests.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/ActivityHandlerTests.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import com.microsoft.bot.schema.*;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/BotFrameworkAdapterTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/BotFrameworkAdapterTests.java
index af3ec53d8..4c68ed00f 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/BotFrameworkAdapterTests.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/BotFrameworkAdapterTests.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import com.fasterxml.jackson.databind.JsonNode;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/BotStateSetTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/BotStateSetTests.java
index 959f73147..16ac34da1 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/BotStateSetTests.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/BotStateSetTests.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import org.junit.Assert;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/InspectionTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/InspectionTests.java
index a20b7bb23..a9ad40382 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/InspectionTests.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/InspectionTests.java
@@ -61,7 +61,7 @@ public void ScenarioWithInspectionMiddlewareOpenAttach() throws IOException {
// (1) send the /INSPECT open command from the emulator to the middleware
Activity openActivity = MessageFactory.text("/INSPECT open");
- TestAdapter inspectionAdapter = new TestAdapter(Channels.TEST);
+ TestAdapter inspectionAdapter = new TestAdapter(Channels.TEST, true);
inspectionAdapter.processActivity(openActivity, turnContext -> {
inspectionMiddleware.processCommand(turnContext).join();
return CompletableFuture.completedFuture(null);
@@ -164,7 +164,7 @@ public void ScenarioWithInspectionMiddlewareOpenAttachWithMention() throws IOExc
// (1) send the /INSPECT open command from the emulator to the middleware
Activity openActivity = MessageFactory.text("/INSPECT open");
- TestAdapter inspectionAdapter = new TestAdapter(Channels.TEST);
+ TestAdapter inspectionAdapter = new TestAdapter(Channels.TEST, true);
inspectionAdapter.processActivity(openActivity, turnContext -> {
inspectionMiddleware.processCommand(turnContext).join();
return CompletableFuture.completedFuture(null);
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MemoryConnectorClient.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MemoryConnectorClient.java
index d18d99dc4..809dab22c 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MemoryConnectorClient.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MemoryConnectorClient.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import com.microsoft.bot.connector.Attachments;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MemoryConversations.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MemoryConversations.java
index 32da8e319..24027f868 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MemoryConversations.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MemoryConversations.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import com.microsoft.bot.connector.Conversations;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MemoryTranscriptTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MemoryTranscriptTests.java
index 00d6fa233..f8b64a8db 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MemoryTranscriptTests.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MemoryTranscriptTests.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import org.junit.Test;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MentionTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MentionTests.java
index 06199d2ad..17ff38043 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MentionTests.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MentionTests.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import com.fasterxml.jackson.databind.ObjectMapper;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MessageFactoryTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MessageFactoryTests.java
index b8fa3bec7..babf68f8c 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MessageFactoryTests.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MessageFactoryTests.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import com.microsoft.bot.builder.adapters.TestAdapter;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MockAppCredentials.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MockAppCredentials.java
index fe949002e..19c23e5c7 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MockAppCredentials.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MockAppCredentials.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import java.util.concurrent.CompletableFuture;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MockConnectorClient.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MockConnectorClient.java
index 757c51894..aa06621de 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MockConnectorClient.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/MockConnectorClient.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import com.microsoft.bot.connector.Attachments;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/OnTurnErrorTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/OnTurnErrorTests.java
index 1dc72d537..9fd3e5287 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/OnTurnErrorTests.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/OnTurnErrorTests.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import com.microsoft.bot.builder.adapters.TestAdapter;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/ShowTypingMiddlewareTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/ShowTypingMiddlewareTests.java
index 6e1393961..daa681438 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/ShowTypingMiddlewareTests.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/ShowTypingMiddlewareTests.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import com.microsoft.bot.builder.adapters.TestAdapter;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/TelemetryMiddlewareTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/TelemetryMiddlewareTests.java
index 126a1aabb..8326fe099 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/TelemetryMiddlewareTests.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/TelemetryMiddlewareTests.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import com.fasterxml.jackson.core.JsonProcessingException;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/TestAdapterTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/TestAdapterTests.java
index 7514e9c0d..b6be7ecc3 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/TestAdapterTests.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/TestAdapterTests.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import com.microsoft.bot.builder.adapters.TestAdapter;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/TranscriptBaseTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/TranscriptBaseTests.java
index 08740c97e..ce3581070 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/TranscriptBaseTests.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/TranscriptBaseTests.java
@@ -1,3 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
package com.microsoft.bot.builder;
import com.codepoetics.protonpack.collectors.CompletableFutures;
diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/adapters/TestAdapter.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/adapters/TestAdapter.java
index 6153529d6..d4425747b 100644
--- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/adapters/TestAdapter.java
+++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/adapters/TestAdapter.java
@@ -19,6 +19,8 @@ public class TestAdapter extends BotAdapter {
private final Queue botReplies = new LinkedList<>();
private int nextId = 0;
private ConversationReference conversationReference;
+ private String locale;
+ private boolean sendTraceActivity = false;
private static class UserTokenKey {
public String connectionName;
@@ -54,6 +56,11 @@ public TestAdapter() {
}
public TestAdapter(String channelId) {
+ this(channelId, false);
+ }
+
+ public TestAdapter(String channelId, boolean sendTraceActivity) {
+ this.sendTraceActivity = sendTraceActivity;
setConversationReference(new ConversationReference() {
{
setChannelId(channelId);
@@ -77,6 +84,7 @@ public TestAdapter(String channelId) {
setId("Conversation1");
}
});
+ setLocale(this.getLocale());
}
});
}
@@ -108,6 +116,7 @@ public TestAdapter(ConversationReference reference) {
setId("Conversation1");
}
});
+ setLocale(this.getLocale());
}
});
}
@@ -123,6 +132,35 @@ public TestAdapter use(Middleware middleware) {
return this;
}
+ /**
+ * Adds middleware to the adapter to register an Storage object on the turn context.
+ * The middleware registers the state objects on the turn context at the start of each turn.
+ * @param storage The storage object to register.
+ * @return The updated adapter.
+ */
+ public TestAdapter useStorage(Storage storage) {
+ if (storage == null) {
+ throw new IllegalArgumentException("Storage cannot be null");
+ }
+ return this.use(new RegisterClassMiddleware(storage));
+ }
+
+ /**
+ * Adds middleware to the adapter to register one or more BotState objects on the turn context.
+ * The middleware registers the state objects on the turn context at the start of each turn.
+ * @param botstates The state objects to register.
+ * @return The updated adapter.
+ */
+ public TestAdapter useBotState(BotState... botstates) {
+ if (botstates == null) {
+ throw new IllegalArgumentException("botstates cannot be null");
+ }
+ for (BotState botState : botstates) {
+ this.use(new RegisterClassMiddleware(botState));
+ }
+ return this;
+ }
+
public CompletableFuture processActivity(Activity activity, BotCallbackHandler callback) {
return CompletableFuture.supplyAsync(() -> {
synchronized (conversationReference()) {
@@ -149,6 +187,9 @@ public CompletableFuture processActivity(Activity activity, BotCallbackHan
if (activity.getTimestamp() == null || activity.getTimestamp().toEpochSecond() == 0)
activity.setTimestamp(OffsetDateTime.now(ZoneId.of("UTC")));
+ if (activity.getLocalTimestamp() == null || activity.getLocalTimestamp().toEpochSecond() == 0)
+ activity.setLocalTimestamp(OffsetDateTime.now());
+
return activity;
}).thenCompose(activity1 -> {
TurnContextImpl context = new TurnContextImpl(this, activity1);
@@ -210,6 +251,12 @@ public CompletableFuture sendActivities(
Thread.sleep(delayMs);
} catch (InterruptedException e) {
}
+ } else if (activity.getType() == ActivityTypes.TRACE) {
+ if (sendTraceActivity) {
+ synchronized (botReplies) {
+ botReplies.add(activity);
+ }
+ }
} else {
synchronized (botReplies) {
botReplies.add(activity);
@@ -452,4 +499,31 @@ public CompletableFuture