Skip to content
This repository was archived by the owner on Dec 4, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ contact [[email protected]](mailto:[email protected]) with any additio

This project uses linting rules to enforce code standardization. These rules are specified in the file [bot-checkstyle.xml](./etc/bot-checkstyle.xml) with [CheckStyle](https://checkstyle.org/) and are hooked to Maven's build cycle.

**INFO**: Since the CheckStyle plugin is hook to the build cycle, this makes the build **fail** in case there are linting warnings in the project files so be sure to check that the code doesn't break any rule.
**INFO**: Since the CheckStyle and PMD plugins are hooked into the build cycle, this makes the build **fail** in cases where there are linting warnings in the project files. Errors will be in the file ./target/checkstyle-result.xml and ./target/pmd.xml.

CheckStyle is available in different flavours:
- [Visual Studio Code plugin](https://marketplace.visualstudio.com/items?itemName=shengchen.vscode-checkstyle)
Expand All @@ -41,6 +41,32 @@ CheckStyle is available in different flavours:

**INFO**: Be sure to configure your IDE to use the file [bot-checkstyle.xml](./etc/bot-checkstyle.xml) instead of the default rules.

## Build and IDE

Any IDE that can import and work with Maven projects should work. As a matter of practice we use the command line to perform Maven builds. If your IDE can be configured to defer build and run to Maven it should also work.
- Java
- We use the [Azul JDK 8](https://www.azul.com/downloads/azure-only/zulu/?version=java-8-lts&architecture=x86-64-bit&package=jdk) to build and test with. While not a requirement to develop the SDK with, it is recommended as this is what Azure is using for Java 1.8. If you do install this JDK, make sure your IDE is targeting that JVM, and your path (from command line) and JAVA_HOME point to that.

- Visual Studio Code
- Extensions
- Java Extension Pack by Microsoft
- Checkstyle for Java by ShengChen (Optional)
- EditorConfig for VS Code by EditorConfig (Recommended)
- Recommended setup
- Open the settings for "Language Support for Java by RedHat" and set:
- Java > Format > Settings: Profile = "BotFramework"
- Java > Format > Settings: Url = "etc/botframework-java-formatter.xml"
- This will format the code (on command) to BotFramework style.

- IntelliJ
- Extensions
- Checkstyle by IDEA
- Eclipse Code Formatter by Vojtech-Krasa (Recommended)
- Recommended setup
- When importing the SDK for the first time, make sure "Auto import" is checked.
- If the Eclipse Code Formatter was installed:
- Got to Settings > Other Settings -> Eclipse Code Formatter, and set the formatter config file to etc/botframework-java-formatter.xml

## Reporting Security Issues

Security issues and bugs should be reported privately, via email, to the Microsoft Security
Expand Down
4 changes: 2 additions & 2 deletions etc/bot-checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@

<!-- Miscellaneous other checks. -->
<!-- See http://checkstyle.sourceforge.net/config_misc.html -->
<module name="RegexpSingleline">
<!-- <module name="RegexpSingleline">
<property name="format" value="\s+$"/>
<property name="minimum" value="0"/>
<property name="maximum" value="0"/>
<property name="message" value="Line has trailing spaces."/>
</module>
</module> -->

<!-- Checks for Headers -->
<!-- See http://checkstyle.sourceforge.net/config_header.html -->
Expand Down
365 changes: 365 additions & 0 deletions etc/botframework-java-formatter.xml

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
import java.util.concurrent.CompletableFuture;

/**
* Middleware to automatically call .SaveChanges() at the end of the turn for all BotState class it is managing.
* Middleware to automatically call .SaveChanges() at the end of the turn for
* all BotState class it is managing.
*/
public class AutoSaveStateMiddleware implements Middleware {
/**
Expand Down Expand Up @@ -67,15 +68,16 @@ public AutoSaveStateMiddleware add(BotState botState) {
}

/**
* Middleware implementation which calls savesChanges automatically at the end of the turn.
* Middleware implementation which calls savesChanges automatically at the end
* of the turn.
*
* @param turnContext The context object for this turn.
* @param next The delegate to call to continue the bot middleware pipeline.
* @param next The delegate to call to continue the bot middleware
* pipeline.
* @return A task representing the asynchronous operation.
*/
@Override
public CompletableFuture<Void> onTurn(TurnContext turnContext, NextDelegate next) {
return next.next()
.thenCompose(result -> botStateSet.saveAllChanges(turnContext));
return next.next().thenCompose(result -> botStateSet.saveAllChanges(turnContext));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ public interface Bot {
/**
* When implemented in a bot, handles an incoming activity.
*
* @param turnContext The context object for this turn. Provides information about the
* incoming activity, and other data needed to process the activity.
* @param turnContext The context object for this turn. Provides information
* about the incoming activity, and other data needed to
* process the activity.
* @return A task that represents the work queued to execute.
*/
CompletableFuture<Void> onTurn(TurnContext turnContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,24 @@
import java.util.concurrent.CompletionException;

/**
* Represents a bot adapter that can connect a bot to a service endpoint.
* This class is abstract.
* <p>The bot adapter encapsulates authentication processes and sends
* activities to and receives activities from the Bot Connector Service. When your
* bot receives an activity, the adapter creates a context object, passes it to your
* bot's application logic, and sends responses back to the user's channel.</p>
* <p>Use {@link #use(Middleware)} to add {@link Middleware} objects
* to your adapter’s middleware collection. The adapter processes and directs
* incoming activities in through the bot middleware pipeline to your bot’s logic
* and then back out again. As each activity flows in and out of the bot, each piece
* of middleware can inspect or act upon the activity, both before and after the bot
* logic runs.</p>
* Represents a bot adapter that can connect a bot to a service endpoint. This
* class is abstract.
* <p>
* The bot adapter encapsulates authentication processes and sends activities to
* and receives activities from the Bot Connector Service. When your bot
* receives an activity, the adapter creates a context object, passes it to your
* bot's application logic, and sends responses back to the user's channel.
* </p>
* <p>
* Use {@link #use(Middleware)} to add {@link Middleware} objects to your
* adapter’s middleware collection. The adapter processes and directs incoming
* activities in through the bot middleware pipeline to your bot’s logic and
* then back out again. As each activity flows in and out of the bot, each piece
* of middleware can inspect or act upon the activity, both before and after the
* bot logic runs.
* </p>
*
* {@link TurnContext}
* {@link Activity}
* {@link Bot}
* {@link Middleware}
* {@link TurnContext} {@link Activity} {@link Bot} {@link Middleware}
*/
public abstract class BotAdapter {
/**
Expand All @@ -42,18 +43,22 @@ public abstract class BotAdapter {
private OnTurnErrorHandler onTurnError;

/**
* Gets the error handler that can catch exceptions in the middleware or application.
* Gets the error handler that can catch exceptions in the middleware or
* application.
*
* @return An error handler that can catch exceptions in the middleware or application.
* @return An error handler that can catch exceptions in the middleware or
* application.
*/
public OnTurnErrorHandler getOnTurnError() {
return onTurnError;
}

/**
* Sets the error handler that can catch exceptions in the middleware or application.
* Sets the error handler that can catch exceptions in the middleware or
* application.
*
* @param withTurnError An error handler that can catch exceptions in the middleware or application.
* @param withTurnError An error handler that can catch exceptions in the
* middleware or application.
*/
public void setOnTurnError(OnTurnErrorHandler withTurnError) {
onTurnError = withTurnError;
Expand All @@ -72,9 +77,9 @@ protected MiddlewareSet getMiddlewareSet() {
* Adds middleware to the adapter's pipeline.
*
* @param middleware The middleware to add.
* @return The updated adapter object.
* Middleware is added to the adapter at initialization time.
* For each turn, the adapter calls middleware in the order in which you added it.
* @return The updated adapter object. Middleware is added to the adapter at
* initialization time. For each turn, the adapter calls middleware in
* the order in which you added it.
*/
public BotAdapter use(Middleware middleware) {
middlewareSet.use(middleware);
Expand All @@ -86,69 +91,85 @@ public BotAdapter use(Middleware middleware) {
*
* @param context The context object for the turn.
* @param activities The activities to send.
* @return A task that represents the work queued to execute.
* If the activities are successfully sent, the task result contains
* an array of {@link ResourceResponse} objects containing the IDs that
* the receiving channel assigned to the activities.
* {@link TurnContext#onSendActivities(SendActivitiesHandler)}
* @return A task that represents the work queued to execute. If the activities
* are successfully sent, the task result contains an array of
* {@link ResourceResponse} objects containing the IDs that the
* receiving channel assigned to the activities.
* {@link TurnContext#onSendActivities(SendActivitiesHandler)}
*/
public abstract CompletableFuture<ResourceResponse[]> sendActivities(TurnContext context,
List<Activity> activities);
public abstract CompletableFuture<ResourceResponse[]> sendActivities(
TurnContext context,
List<Activity> activities
);

/**
* When overridden in a derived class, replaces an existing activity in the
* conversation.
*
* @param context The context object for the turn.
* @param activity New replacement activity.
* @return A task that represents the work queued to execute.
* If the activity is successfully sent, the task result contains
* a {@link ResourceResponse} object containing the ID that the receiving
* channel assigned to the activity.
* <p>Before calling this, set the ID of the replacement activity to the ID
* of the activity to replace.</p>
* {@link TurnContext#onUpdateActivity(UpdateActivityHandler)}
* @return A task that represents the work queued to execute. If the activity is
* successfully sent, the task result contains a
* {@link ResourceResponse} object containing the ID that the receiving
* channel assigned to the activity.
* <p>
* Before calling this, set the ID of the replacement activity to the ID
* of the activity to replace.
* </p>
* {@link TurnContext#onUpdateActivity(UpdateActivityHandler)}
*/
public abstract CompletableFuture<ResourceResponse> updateActivity(TurnContext context,
Activity activity);
public abstract CompletableFuture<ResourceResponse> updateActivity(
TurnContext context,
Activity activity
);

/**
* When overridden in a derived class, deletes an existing activity in the
* conversation.
*
* @param context The context object for the turn.
* @param reference Conversation reference for the activity to delete.
* @return A task that represents the work queued to execute.
* The {@link ConversationReference#getActivityId} of the conversation
* reference identifies the activity to delete.
* {@link TurnContext#onDeleteActivity(DeleteActivityHandler)}
* @return A task that represents the work queued to execute. The
* {@link ConversationReference#getActivityId} of the conversation
* reference identifies the activity to delete.
* {@link TurnContext#onDeleteActivity(DeleteActivityHandler)}
*/
public abstract CompletableFuture<Void> deleteActivity(TurnContext context, ConversationReference reference);
public abstract CompletableFuture<Void> deleteActivity(
TurnContext context,
ConversationReference reference
);

/**
* Starts activity processing for the current bot turn.
*
* The adapter calls middleware in the order in which you added it.
* The adapter passes in the context object for the turn and a next delegate,
* and the middleware calls the delegate to pass control to the next middleware
* in the pipeline. Once control reaches the end of the pipeline, the adapter calls
* the {@code callback} method. If a middleware component does not call
* the next delegate, the adapter does not call any of the subsequent middleware’s
* {@link Middleware#onTurn(TurnContext, NextDelegate)}
* methods or the callback method, and the pipeline short circuits.
* The adapter calls middleware in the order in which you added it. The adapter
* passes in the context object for the turn and a next delegate, and the
* middleware calls the delegate to pass control to the next middleware in the
* pipeline. Once control reaches the end of the pipeline, the adapter calls the
* {@code callback} method. If a middleware component does not call the next
* delegate, the adapter does not call any of the subsequent middleware’s
* {@link Middleware#onTurn(TurnContext, NextDelegate)} methods or the callback
* method, and the pipeline short circuits.
*
* <p>When the turn is initiated by a user activity (reactive messaging), the
* <p>
* When the turn is initiated by a user activity (reactive messaging), the
* callback method will be a reference to the bot's
* {@link Bot#onTurn(TurnContext)} method. When the turn is
* initiated by a call to {@link #continueConversation(String, ConversationReference, BotCallbackHandler)}
* (proactive messaging), the callback method is the callback method that was provided in the call.</p>
* {@link Bot#onTurn(TurnContext)} method. When the turn is initiated by a call
* to
* {@link #continueConversation(String, ConversationReference, BotCallbackHandler)}
* (proactive messaging), the callback method is the callback method that was
* provided in the call.
* </p>
*
* @param context The turn's context object.
* @param callback A callback method to run at the end of the pipeline.
* @return A task that represents the work queued to execute.
* @throws NullPointerException {@code context} is null.
*/
protected CompletableFuture<Void> runPipeline(TurnContext context, BotCallbackHandler callback) {
protected CompletableFuture<Void> runPipeline(
TurnContext context,
BotCallbackHandler callback
) {
BotAssert.contextNotNull(context);

// Call any registered Middleware Components looking for ReceiveActivity()
Expand All @@ -175,24 +196,30 @@ protected CompletableFuture<Void> runPipeline(TurnContext context, BotCallbackHa
* Sends a proactive message to a conversation.
*
* @param botAppId The application ID of the bot. This parameter is ignored in
* single tenant the Adapters (Console, Test, etc) but is critical to the BotFrameworkAdapter
* which is multi-tenant aware.
* single tenant the Adapters (Console, Test, etc) but is
* critical to the BotFrameworkAdapter which is multi-tenant
* aware.
* @param reference A reference to the conversation to continue.
* @param callback The method to call for the resulting bot turn.
* @return A task that represents the work queued to execute.
* Call this method to proactively send a message to a conversation.
* Most channels require a user to initiate a conversation with a bot
* before the bot can send activities to the user.
* @return A task that represents the work queued to execute. Call this method
* to proactively send a message to a conversation. Most channels
* require a user to initiate a conversation with a bot before the bot
* can send activities to the user.
*
* {@link #runPipeline(TurnContext, BotCallbackHandler)}
* {@link #runPipeline(TurnContext, BotCallbackHandler)}
*/
public CompletableFuture<Void> continueConversation(String botAppId,
ConversationReference reference,
BotCallbackHandler callback) {
public CompletableFuture<Void> continueConversation(
String botAppId,
ConversationReference reference,
BotCallbackHandler callback
) {

CompletableFuture<Void> pipelineResult = new CompletableFuture<>();

try (TurnContextImpl context = new TurnContextImpl(this, reference.getContinuationActivity())) {
try (TurnContextImpl context = new TurnContextImpl(
this,
reference.getContinuationActivity()
)) {
pipelineResult = runPipeline(context, callback);
} catch (Exception e) {
pipelineResult.completeExceptionally(e);
Expand Down
Loading