Add annotation to allow bot to get botSession

A method annotated with @AfterBotRegistration will be invoked after
the bot is registered.

Optionally the method can have a parameter of
type BotSession to get passed the BotSession the bot was created with.
This commit is contained in:
chase 2018-12-19 22:09:04 +01:00
parent 27e0751b7e
commit ad195d8d59
3 changed files with 163 additions and 4 deletions

View File

@ -0,0 +1,20 @@
package org.telegram.telegrambots.starter;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.generics.BotSession;
import org.telegram.telegrambots.meta.generics.LongPollingBot;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicated that the Method of a Class extending {@link LongPollingBot} will be called after the bot was registered
* If the Method has a single Parameter of type {@link BotSession}, the method get passed the bot session the bot was registered with
* <br><br>
* <p>The bot session passed is the ones returned by {@link TelegramBotsApi#registerBot(LongPollingBot)}</p>
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AfterBotRegistration {}

View File

@ -1,13 +1,20 @@
package org.telegram.telegrambots.starter;
import java.util.List;
import java.util.Objects;
import org.springframework.beans.factory.InitializingBean;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import org.telegram.telegrambots.meta.generics.BotSession;
import org.telegram.telegrambots.meta.generics.LongPollingBot;
import org.telegram.telegrambots.meta.generics.WebhookBot;
import org.telegram.telegrambots.meta.logging.BotLogger;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
import static java.lang.String.format;
/**
* Receives all beand which are #LongPollingBot and #WebhookBot and register them in #TelegramBotsApi.
@ -33,7 +40,8 @@ public class TelegramBotInitializer implements InitializingBean {
public void afterPropertiesSet() throws Exception {
try {
for (LongPollingBot bot : longPollingBots) {
telegramBotsApi.registerBot(bot);
BotSession session = telegramBotsApi.registerBot(bot);
handleAfterRegistrationHook(bot, session);
}
for (WebhookBot bot : webHookBots) {
telegramBotsApi.registerBot(bot);
@ -42,4 +50,47 @@ public class TelegramBotInitializer implements InitializingBean {
throw new RuntimeException(e);
}
}
private void handleAnnotatedMethod(Object bot, Method method, BotSession session) throws InvocationTargetException, IllegalAccessException {
if (method.getParameterCount() > 1) {
BotLogger.warn(this.getClass().getSimpleName(),
format("Method %s of Type %s has too many parameters",
method.getName(),
method.getDeclaringClass().getCanonicalName()
)
);
return;
}
if (method.getParameterCount() == 0) {
method.invoke(bot);
return;
}
if (method.getParameterTypes()[0].equals(BotSession.class)) {
method.invoke(bot, session);
return;
}
BotLogger.warn(this.getClass().getSimpleName(),
format("Method %s of Type %s has invalid parameter type",
method.getName(),
method.getDeclaringClass().getCanonicalName()
)
);
}
private void handleAfterRegistrationHook(Object bot, BotSession botSession) {
for (Method m : bot.getClass().getMethods()) {
Stream.of(m.getAnnotations()).forEach(annotation -> System.out.println(annotation.annotationType().getName()));
if (m.getAnnotation(AfterBotRegistration.class) != null) {
try {
handleAnnotatedMethod(bot, m, botSession);
} catch (InvocationTargetException | IllegalAccessException e) {
BotLogger.error(this.getClass().getSimpleName(),
format("Couldn't invoke Method %s of Type %s",
m.getName(), m.getDeclaringClass().getCanonicalName()
)
);
}
}
}
}
}

View File

@ -0,0 +1,88 @@
package org.telegram.telegrambots.starter;
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.generics.BotSession;
import org.telegram.telegrambots.meta.generics.LongPollingBot;
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
public class TestTelegramBotStarterRegistrationHooks {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(MockTelegramBotsApi.class, TelegramBotStarterConfiguration.class));
// Terrible workaround for mockito loosing annotations on methods
private static boolean hookCalled = false;
private static boolean hookCalledWithSession = false;
private static final DefaultBotSession someBotSession = new DefaultBotSession();
private static final TelegramBotsApi mockTelegramBotsApi = mock(TelegramBotsApi.class);
@Test
public void longPollingBotWithAnnotatedMethodshouldBeCalled() throws TelegramApiRequestException {
when(mockTelegramBotsApi.registerBot(any(LongPollingBot.class))).thenReturn(someBotSession);
this.contextRunner.withUserConfiguration(LongPollingBotConfig.class)
.run((context) -> {
assertThat(context).hasSingleBean(AnnotatedLongPollingBot.class);
final LongPollingBot bot = context.getBean(LongPollingBot.class);
final TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class);
assertThat(hookCalled).isTrue();
assertThat(hookCalledWithSession).isTrue();
verify(telegramBotsApi, times(1)).registerBot(bot);
verifyNoMoreInteractions(telegramBotsApi);
});
}
@Configuration
static class MockTelegramBotsApi{
@Bean
public TelegramBotsApi telegramBotsApi() {
return mockTelegramBotsApi;
}
}
@Configuration
static class LongPollingBotConfig{
@Bean
public LongPollingBot longPollingBot() { return new AnnotatedLongPollingBot(); }
}
static class AnnotatedLongPollingBot extends TelegramLongPollingBot {
@Override
public void onUpdateReceived(final Update update) {}
@Override
public String getBotUsername() { return null; }
@Override
public String getBotToken() { return null; }
@AfterBotRegistration
public void afterBotHook() {
hookCalled = true;
}
@AfterBotRegistration
public void afterBotHookWithSession(BotSession session) {
hookCalledWithSession = session.equals(someBotSession);
}
}
}