commit
18412d9c98
@ -12,20 +12,21 @@ import org.telegram.abilitybots.api.objects.*;
|
||||
import org.telegram.abilitybots.api.sender.DefaultSender;
|
||||
import org.telegram.abilitybots.api.sender.MessageSender;
|
||||
import org.telegram.abilitybots.api.sender.SilentSender;
|
||||
import org.telegram.abilitybots.api.util.AbilityExtension;
|
||||
import org.telegram.abilitybots.api.util.AbilityUtils;
|
||||
import org.telegram.abilitybots.api.util.Pair;
|
||||
import org.telegram.abilitybots.api.util.Trio;
|
||||
import org.telegram.telegrambots.bots.DefaultAbsSender;
|
||||
import org.telegram.telegrambots.bots.DefaultBotOptions;
|
||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
||||
import org.telegram.telegrambots.meta.api.methods.GetFile;
|
||||
import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatAdministrators;
|
||||
import org.telegram.telegrambots.meta.api.methods.send.SendDocument;
|
||||
import org.telegram.telegrambots.meta.api.objects.Message;
|
||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||
import org.telegram.telegrambots.meta.api.objects.User;
|
||||
import org.telegram.telegrambots.bots.DefaultAbsSender;
|
||||
import org.telegram.telegrambots.bots.DefaultBotOptions;
|
||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
||||
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
||||
import org.telegram.telegrambots.meta.logging.BotLogger;
|
||||
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
@ -36,7 +37,9 @@ import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
@ -93,7 +96,7 @@ import static org.telegram.abilitybots.api.util.AbilityUtils.*;
|
||||
* @author Abbas Abou Daya
|
||||
*/
|
||||
@SuppressWarnings({"ConfusingArgumentToVarargsMethod", "UnusedReturnValue", "WeakerAccess", "unused", "ConstantConditions"})
|
||||
public abstract class BaseAbilityBot extends DefaultAbsSender {
|
||||
public abstract class BaseAbilityBot extends DefaultAbsSender implements AbilityExtension {
|
||||
private static final String TAG = BaseAbilityBot.class.getSimpleName();
|
||||
|
||||
// DB objects
|
||||
@ -611,22 +614,38 @@ public abstract class BaseAbilityBot extends DefaultAbsSender {
|
||||
*/
|
||||
private void registerAbilities() {
|
||||
try {
|
||||
abilities = stream(this.getClass().getMethods())
|
||||
.filter(method -> method.getReturnType().equals(Ability.class))
|
||||
.map(this::returnAbility)
|
||||
// Collect all classes that implement AbilityExtension declared in the bot
|
||||
List<AbilityExtension> extensions = stream(getClass().getMethods())
|
||||
.filter(checkReturnType(AbilityExtension.class))
|
||||
.map(returnExtension(this))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Add the bot itself as it is an AbilityExtension
|
||||
extensions.add(this);
|
||||
|
||||
// Extract all abilities from every single extension instance
|
||||
abilities = extensions.stream()
|
||||
.flatMap(ext -> stream(ext.getClass().getMethods())
|
||||
.filter(checkReturnType(Ability.class))
|
||||
.map(returnAbility(ext)))
|
||||
// Abilities are immutable, build it respectively
|
||||
.collect(ImmutableMap::<String, Ability>builder,
|
||||
(b, a) -> b.put(a.name(), a),
|
||||
(b1, b2) -> b1.putAll(b2.build()))
|
||||
.build();
|
||||
|
||||
Stream<Reply> methodReplies = stream(this.getClass().getMethods())
|
||||
.filter(method -> method.getReturnType().equals(Reply.class))
|
||||
.map(this::returnReply);
|
||||
// Extract all replies from every single extension instance
|
||||
Stream<Reply> extensionReplies = extensions.stream()
|
||||
.flatMap(ext -> stream(ext.getClass().getMethods())
|
||||
.filter(checkReturnType(Reply.class))
|
||||
.map(returnReply(ext)));
|
||||
|
||||
// Replies can be standalone or attached to abilities, fetch those too
|
||||
Stream<Reply> abilityReplies = abilities.values().stream()
|
||||
.flatMap(ability -> ability.replies().stream());
|
||||
|
||||
replies = Stream.concat(methodReplies, abilityReplies).collect(
|
||||
// Now create the replies registry (list)
|
||||
replies = Stream.concat(abilityReplies, extensionReplies).collect(
|
||||
ImmutableList::<Reply>builder,
|
||||
Builder::add,
|
||||
(b1, b2) -> b1.addAll(b2.build()))
|
||||
@ -635,37 +654,65 @@ public abstract class BaseAbilityBot extends DefaultAbsSender {
|
||||
BotLogger.error(TAG, "Duplicate names found while registering abilities. Make sure that the abilities declared don't clash with the reserved ones.", e);
|
||||
throw propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clazz the type to be tested
|
||||
* @return a predicate testing the return type of the method corresponding to the class parameter
|
||||
*/
|
||||
private Predicate<Method> checkReturnType(Class<?> clazz) {
|
||||
return method -> clazz.isAssignableFrom(method.getReturnType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the method and retrieves its return {@link Reply}.
|
||||
*
|
||||
* @param obj an bot or extension that this method is invoked with
|
||||
* @return a {@link Function} which returns the {@link Reply} returned by the given method
|
||||
*/
|
||||
private Function<? super Method, AbilityExtension> returnExtension(Object obj) {
|
||||
return method -> {
|
||||
try {
|
||||
return (AbilityExtension) method.invoke(obj);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
BotLogger.error("Could not add ability extension", TAG, e);
|
||||
throw propagate(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the method and retrieves its return {@link Ability}.
|
||||
*
|
||||
* @param method a method that returns an ability
|
||||
* @return the ability returned by the method
|
||||
* @param obj an bot or extension that this method is invoked with
|
||||
* @return a {@link Function} which returns the {@link Ability} returned by the given method
|
||||
*/
|
||||
private Ability returnAbility(Method method) {
|
||||
try {
|
||||
return (Ability) method.invoke(this);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
BotLogger.error("Could not add ability", TAG, e);
|
||||
throw propagate(e);
|
||||
}
|
||||
private Function<? super Method, Ability> returnAbility(Object obj) {
|
||||
return method -> {
|
||||
try {
|
||||
return (Ability) method.invoke(obj);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
BotLogger.error("Could not add ability", TAG, e);
|
||||
throw propagate(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the method and retrieves its returned Reply.
|
||||
* Invokes the method and retrieves its return {@link Reply}.
|
||||
*
|
||||
* @param method a method that returns a reply
|
||||
* @return the reply returned by the method
|
||||
* @param obj an bot or extension that this method is invoked with
|
||||
* @return a {@link Function} which returns the {@link Reply} returned by the given method
|
||||
*/
|
||||
private Reply returnReply(Method method) {
|
||||
try {
|
||||
return (Reply) method.invoke(this);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
BotLogger.error("Could not add reply", TAG, e);
|
||||
throw propagate(e);
|
||||
}
|
||||
private Function<? super Method, Reply> returnReply(Object obj) {
|
||||
return method -> {
|
||||
try {
|
||||
return (Reply) method.invoke(obj);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
BotLogger.error("Could not add reply", TAG, e);
|
||||
throw propagate(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void postConsumption(Pair<MessageContext, Ability> pair) {
|
||||
|
@ -0,0 +1,7 @@
|
||||
package org.telegram.abilitybots.api.util;
|
||||
|
||||
/**
|
||||
* An interface to mark a class as an extension. Similar to when a method returns an Ability, it is added to the bot, a method which returns an AbilityExtension will add all Abilities or Replies from this Extension to the bot.
|
||||
*/
|
||||
public interface AbilityExtension {
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package org.telegram.abilitybots.api.bot;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.telegram.abilitybots.api.objects.Ability;
|
||||
import org.telegram.abilitybots.api.util.AbilityExtension;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance;
|
||||
import static org.telegram.abilitybots.api.objects.Locality.ALL;
|
||||
import static org.telegram.abilitybots.api.objects.Privacy.PUBLIC;
|
||||
|
||||
public class ExtensionTest {
|
||||
private ExtensionUsingBot bot;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
bot = new ExtensionUsingBot();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodReturningAbilities() {
|
||||
assertTrue("Failed to find Ability in directly declared in root extension/bot", hasAbilityNamed("direct"));
|
||||
assertTrue("Failed to find Ability in directly declared in extension returned by method returning the AbilityExtension class", hasAbilityNamed("returningSuperClass0abc"));
|
||||
assertTrue("Failed to find Ability in directly declared in extension returned by method returning the AbilityExtension subclass", hasAbilityNamed("returningSubClass0abc"));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws IOException {
|
||||
bot.db.clear();
|
||||
bot.db.close();
|
||||
}
|
||||
|
||||
private boolean hasAbilityNamed(String name) {
|
||||
return bot.abilities().values().stream().map(Ability::name).anyMatch(name::equals);
|
||||
}
|
||||
|
||||
public static class ExtensionUsingBot extends AbilityBot {
|
||||
public ExtensionUsingBot() {
|
||||
super("", "", offlineInstance("testing"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int creatorId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public AbilityBotExtension methodReturningExtensionSubClass() {
|
||||
return new AbilityBotExtension("returningSubClass");
|
||||
}
|
||||
|
||||
public AbilityExtension methodReturningExtensionSuperClass() {
|
||||
return new AbilityBotExtension("returningSuperClass");
|
||||
}
|
||||
|
||||
public Ability methodReturningAbility() {
|
||||
return Ability.builder()
|
||||
.name("direct")
|
||||
.info("Test ability")
|
||||
.locality(ALL)
|
||||
.privacy(PUBLIC)
|
||||
.action(messageContext -> {
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AbilityBotExtension implements AbilityExtension {
|
||||
private String name;
|
||||
|
||||
public AbilityBotExtension(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Ability abc() {
|
||||
return Ability.builder()
|
||||
.name(name + "0abc")
|
||||
.info("Test ability")
|
||||
.locality(ALL)
|
||||
.privacy(PUBLIC)
|
||||
.action(ctx -> {
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user