Skip to content

Commit

Permalink
Merge pull request #406 from deutschebank/spring-bot-master-db
Browse files Browse the repository at this point in the history
Compatibility With Spring-boot 3x
  • Loading branch information
vaibhav-db committed Jul 17, 2023
2 parents c915e2a + db58e07 commit e732e4d
Show file tree
Hide file tree
Showing 5 changed files with 867 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import javax.annotation.PostConstruct;

import org.finos.springbot.ChatWorkflowConfig;
import org.finos.springbot.teams.bot.BotController;
import org.finos.springbot.teams.content.TeamsContentConfig;
import org.finos.springbot.teams.content.serialization.TeamsHTMLParser;
import org.finos.springbot.teams.content.serialization.TeamsMarkupWriter;
Expand Down Expand Up @@ -42,6 +43,7 @@
import org.finos.springbot.workflow.form.FormValidationProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
Expand All @@ -59,7 +61,6 @@
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.microsoft.bot.builder.TurnContext;
import com.microsoft.bot.integration.BotFrameworkHttpAdapter;
import com.microsoft.bot.integration.spring.BotController;
import com.microsoft.bot.schema.ChannelAccount;

/**
Expand All @@ -78,7 +79,7 @@
TeamsConversationsConfig.class
})
@Profile("teams")
public class TeamsWorkflowConfig {
public class TeamsWorkflowConfig implements InitializingBean {

private static final Logger LOG = LoggerFactory.getLogger(TeamsWorkflowConfig.class);

Expand Down Expand Up @@ -231,10 +232,22 @@ public AddressingChecker teamsAddressingChecker(TeamsConversations conv) {
* Templates don't load properly with a fat jar.
* @see https://github.com/finos/spring-bot/issues/340
*/
@PostConstruct
public void setResourceLoaderClassLoader() {
resourceLoader.setClassLoader(this.getClass().getClassLoader());
}
// @PostConstruct
// public void setResourceLoaderClassLoader() {
// resourceLoader.setClassLoader(this.getClass().getClassLoader());
// }

/**
* Templates don't load properly with a fat jar.
* @see https://github.com/finos/spring-bot/issues/340
* and Spring-boot:3x suuport
* https://github.com/finos/spring-bot/issues/405
*
*/
@Override
public void afterPropertiesSet() throws Exception {
resourceLoader.setClassLoader(this.getClass().getClassLoader());
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package org.finos.springbot.teams.bot;


import com.microsoft.bot.builder.Bot;
import com.microsoft.bot.connector.authentication.AuthenticationException;
import com.microsoft.bot.integration.BotFrameworkHttpAdapter;
import com.microsoft.bot.schema.Activity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

/**
* <p>
* This class is part of <code>com.microsoft.bot:bot-integration-spring</code>
* As Microsoft sdk does't support the spring-boot:3x, so we have copied the class and made change that are compatible with spring-boot:3x
* </p>
*
*<p>
* This is the default controller that will receive incoming Channel Activity
* messages.
*</p>
* <p>
* This controller is suitable in most cases. Bots that want to use this
* controller should do so by using the @Import({BotController.class})
* annotation. See any of the samples Application class for an example.
* </p>
*/
@RestController
public class BotController {
/**
* The slf4j Logger to use. Note that slf4j is configured by providing Log4j
* dependencies in the POM, and corresponding Log4j configuration in the
* 'resources' folder.
*/
private Logger logger = LoggerFactory.getLogger(BotController.class);

/**
* The BotFrameworkHttpAdapter to use. Note it is provided by dependency
* injection via the constructor.
*/
private final BotFrameworkHttpAdapter adapter;

/**
* The Bot to use. Note it is provided by dependency
* injection via the constructor.
*/
private final Bot bot;

/**
* Spring will use this constructor for creation.
*
* <p>
* The Bot application should define class that implements {@link Bot} and
* annotate it with @Component.
* </p>
*
* @see BotDependencyConfiguration
*
* @param withAdapter The BotFrameworkHttpAdapter to use.
* @param withBot The Bot to use.
*/
public BotController(BotFrameworkHttpAdapter withAdapter, Bot withBot) {
adapter = withAdapter;
bot = withBot;
}

/**
* This will receive incoming Channel Activities.
*
* @param activity The incoming Activity.
* @param authHeader The incoming Authorization header.
* @return The request response.
*/
@PostMapping("/api/messages")
public CompletableFuture<ResponseEntity<Object>> incoming(
@RequestBody Activity activity,
@RequestHeader(value = "Authorization", defaultValue = "") String authHeader
) {

return adapter.processIncomingActivity(authHeader, activity, bot)

.handle((result, exception) -> {
if (exception == null) {
if (result != null) {
return new ResponseEntity<>(
result.getBody(),
HttpStatus.valueOf(result.getStatus())
);
}
return ResponseEntity.accepted().build();
}

logger.error("Exception handling message", exception);

if (exception instanceof CompletionException) {
if (exception.getCause() instanceof AuthenticationException) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
} else {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
} else {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package org.finos.springbot.teams.bot;


import java.util.concurrent.ExecutorService;

import org.springframework.context.annotation.Bean;

import com.microsoft.bot.builder.ConversationState;
import com.microsoft.bot.builder.MemoryStorage;
import com.microsoft.bot.builder.Storage;
import com.microsoft.bot.builder.UserState;
import com.microsoft.bot.builder.inspection.InspectionState;
import com.microsoft.bot.connector.ExecutorFactory;
import com.microsoft.bot.connector.authentication.AuthenticationConfiguration;
import com.microsoft.bot.connector.authentication.ChannelProvider;
import com.microsoft.bot.connector.authentication.CredentialProvider;
import com.microsoft.bot.integration.BotFrameworkHttpAdapter;
import com.microsoft.bot.integration.ClasspathPropertiesConfiguration;
import com.microsoft.bot.integration.Configuration;
import com.microsoft.bot.integration.ConfigurationChannelProvider;
import com.microsoft.bot.integration.ConfigurationCredentialProvider;

/**
* <p>
* This class is part of <code>com.microsoft.bot:bot-integration-spring</code>
* As Microsoft sdk does't support the spring-boot:3x, so we have copied the class and made change that are compatible with spring-boot:3x
* </p>
*
* <p>
* This provides the default dependency creation for a Bot application.
*</p>
* <p>
* This class should be subclassed by a class with the
* {@link org.springframework.context.annotation.Configuration} annotation (or
* SpringBootApplication annotation).
* </p>
*
* <p>
* The Bot should be annotated with @Component, possibly including @AutoWired to
* indicate which constructor to use.
* </p>
*/
public abstract class BotDependencyConfiguration {
/**
* Returns an ExecutorService.
*
* <p>
* For now, return the bot-connector ExecutorService. This is an area of
* consideration. The goal here is to have a common ExecutorService to avoid
* multiple thread pools.
* </p>
*
* @return An ExecutorService.
*/
@Bean
public ExecutorService getExecutorService() {
return ExecutorFactory.getExecutor();
}

/**
* Returns the Configuration for the application.
*
* By default, it uses the {@link ClasspathPropertiesConfiguration} class.
* Default scope of Singleton.
*
* @return A Configuration object.
*/
@Bean
public Configuration getConfiguration() {
return new ClasspathPropertiesConfiguration();
}


/**
* Returns the AuthenticationConfiguration for the application.
*
* By default, it uses the {@link AuthenticationConfiguration} class.
* Default scope of Singleton.
* @param configuration The Configuration object to read from.
* @return An AuthenticationConfiguration object.
*/
@Bean
public AuthenticationConfiguration getAuthenticationConfiguration(Configuration configuration) {
return new AuthenticationConfiguration();
}

/**
* Returns the CredentialProvider for the application.
*
* By default, it uses the {@link ConfigurationCredentialProvider} class.
* Default scope of Singleton.
*
* @param configuration The Configuration object to read from.
* @return A CredentialProvider object.
*
* @see #getConfiguration()
*/
@Bean
public CredentialProvider getCredentialProvider(Configuration configuration) {
return new ConfigurationCredentialProvider(configuration);
}

/**
* Returns the ChannelProvider for the application.
*
* By default, it uses the {@link ConfigurationChannelProvider} class. Default
* scope of Singleton.
*
* @param configuration The Configuration object to read from.
* @return A ChannelProvider object.
*
* @see #getConfiguration()
*/
@Bean
public ChannelProvider getChannelProvider(Configuration configuration) {
return new ConfigurationChannelProvider(configuration);
}

/**
* Returns the BotFrameworkHttpAdapter for the application.
*
* By default, it uses the {@link BotFrameworkHttpAdapter} class. Default scope
* of Singleton.
*
* @param configuration The Configuration object to read from.
* @return A BotFrameworkHttpAdapter object.
*
* @see #getConfiguration()
*/
@Bean
public BotFrameworkHttpAdapter getBotFrameworkHttpAdaptor(Configuration configuration) {
return new BotFrameworkHttpAdapter(configuration);
}

/**
* Returns a {@link Storage} object. Default scope of Singleton.
*
* @return A Storage object.
*/
@Bean
public Storage getStorage() {
return new MemoryStorage();
}

/**
* Returns a ConversationState object. Default scope of Singleton.
*
* @param storage The Storage object to use.
* @return A ConversationState object.
*/
@Bean
public ConversationState getConversationState(Storage storage) {
return new ConversationState(storage);
}

/**
* Returns a UserState object. Default scope of Singleton.
*
* @param storage The Storage object to use.
* @return A UserState object.
*/
@Bean
public UserState getUserState(Storage storage) {
return new UserState(storage);
}

/**
* Creates an InspectionState used by
* {@link com.microsoft.bot.builder.inspection.InspectionMiddleware}. Default
* scope of Singleton.
*
* @param storage The Storage to use.
* {@link BotDependencyConfiguration#getStorage()}
* @return An InspectionState object that uses the specified storage.
*/
@Bean
public InspectionState getInspectionState(Storage storage) {
return new InspectionState(storage);
}
}
Loading

0 comments on commit e732e4d

Please sign in to comment.