From b2a2f04ba389fcc182567442a6837cb6d64514c6 Mon Sep 17 00:00:00 2001 From: Davide Polonio Date: Wed, 19 Apr 2023 18:08:22 +0200 Subject: [PATCH] feat: add error-prone library, done translations --- .mvn/jvm.config | 10 +++ pom.xml | 16 ++++- .../mezzotre/telegram/command/NotFound.java | 26 +++++-- .../polpetta/mezzotre/util/ServiceModule.java | 16 ++++- src/main/resources/i18n/message.properties | 4 ++ .../resources/i18n/message_en_US.properties | 4 ++ src/main/resources/i18n/message_it.properties | 12 ++++ .../resources/i18n/message_it_IT.properties | 12 ++++ .../resources/template/telegram/notFound.vm | 3 + .../mezzotre/util/ServiceModuleTest.java | 72 +++++++++++++++++++ 10 files changed, 166 insertions(+), 9 deletions(-) create mode 100644 .mvn/jvm.config create mode 100644 src/main/resources/template/telegram/notFound.vm create mode 100644 src/test/java/com/github/polpetta/mezzotre/util/ServiceModuleTest.java diff --git a/.mvn/jvm.config b/.mvn/jvm.config new file mode 100644 index 0000000..32599ce --- /dev/null +++ b/.mvn/jvm.config @@ -0,0 +1,10 @@ +--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED +--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED +--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED diff --git a/pom.xml b/pom.xml index bb22800..66b4eb0 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,7 @@ 2.13.3 5.9.1 5.1.0 + 2.18.0 @@ -240,7 +241,11 @@ 31.1-jre - + + com.google.errorprone + error_prone_annotations + ${error-prone.version} + @@ -279,12 +284,19 @@ maven-compiler-plugin - 3.6.2 + 3.8.1 -parameters + -XDcompilePolicy=simple + -Xplugin:ErrorProne + + com.google.errorprone + error_prone_core + ${error-prone.version} + io.jooby jooby-apt diff --git a/src/main/java/com/github/polpetta/mezzotre/telegram/command/NotFound.java b/src/main/java/com/github/polpetta/mezzotre/telegram/command/NotFound.java index deef282..ad42361 100644 --- a/src/main/java/com/github/polpetta/mezzotre/telegram/command/NotFound.java +++ b/src/main/java/com/github/polpetta/mezzotre/telegram/command/NotFound.java @@ -1,5 +1,6 @@ package com.github.polpetta.mezzotre.telegram.command; +import com.github.polpetta.mezzotre.i18n.TemplateContentGenerator; import com.github.polpetta.mezzotre.orm.model.TgChat; import com.google.inject.assistedinject.Assisted; import com.pengrad.telegrambot.model.Update; @@ -9,7 +10,9 @@ import java.util.Collections; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; import javax.inject.Inject; +import javax.inject.Named; /** * Generates a "Command not found" message @@ -19,12 +22,20 @@ import javax.inject.Inject; * @see com.github.polpetta.mezzotre.telegram.callbackquery.NotFound for the event-based version */ class NotFound implements Processor { + private static final String CMD_CTX_NAME = "cmdName"; private final String commandName; + private final TemplateContentGenerator templateContentGenerator; + private final Executor threadPool; @Inject - public NotFound(@Assisted String commandName) { + public NotFound( + @Assisted String commandName, + TemplateContentGenerator templateContentGenerator, + @Named("eventThreadPool") Executor threadPool) { this.commandName = commandName; + this.templateContentGenerator = templateContentGenerator; + this.threadPool = threadPool; } @Override @@ -35,10 +46,13 @@ class NotFound implements Processor { @Override public CompletableFuture>> process(TgChat chat, Update update) { // FIXME complete it with: localization, callbackQuery to show help message - return CompletableFuture.completedFuture(update) - .thenApply( - ignored -> - Optional.of( - new SendMessage(chat.getId(), "Command " + commandName + " is not valid"))); + return CompletableFuture.supplyAsync( + () -> + templateContentGenerator.mergeTemplate( + ctx -> ctx.put(CMD_CTX_NAME, commandName), + chat.getLocale(), + "template/telegram/notFound.vm"), + threadPool) + .thenApply(text -> Optional.of(new SendMessage(chat.getId(), text))); } } diff --git a/src/main/java/com/github/polpetta/mezzotre/util/ServiceModule.java b/src/main/java/com/github/polpetta/mezzotre/util/ServiceModule.java index e9db94d..f509088 100644 --- a/src/main/java/com/github/polpetta/mezzotre/util/ServiceModule.java +++ b/src/main/java/com/github/polpetta/mezzotre/util/ServiceModule.java @@ -13,7 +13,21 @@ import javax.inject.Inject; import javax.inject.Named; import org.jetbrains.annotations.NotNull; -// FIXME doc, tests(?) +/** + * This Jooby {@link Extension} allows to start and execute services that implement {@link Service} + * class. This allows implementation of this interface to be automatically started. Services need to + * me listed by the named key {@code "services"}, which is a {@link List} of services passed by the + * {@link com.google.inject.Injector}. + * + *

The module handles the services start and stop when the whole JVM is stopped, allowing a + * graceful service shutdown. + * + * @author Davide Polonio + * @since 1.0 + * @see Guava Service Wiki + * explained + * @see ServiceManager + */ public class ServiceModule implements Extension { private final ServiceManager serviceManager; diff --git a/src/main/resources/i18n/message.properties b/src/main/resources/i18n/message.properties index d022a29..f8458cd 100644 --- a/src/main/resources/i18n/message.properties +++ b/src/main/resources/i18n/message.properties @@ -10,6 +10,8 @@ changeLanguage.english=English changeLanguage.italian=Italian changeLanguage.cmdDescription=Select the new language I will use to speak to you changeLanguage.inlineKeyboardButtonName=Change language +selectLanguageTutorial.english=English +selectLanguageTutorial.italian=Italian spell.speakWithAnimals=Speak with animals selectLanguageTutorial.showMeTutorialInlineKeyboardButtonName=Show me what you can do! help.notShownYet=It seems you haven''t checked out what I can do yet! To have a complete list of my abilities, type /help in chat at any time! @@ -17,3 +19,5 @@ help.buttonBelow=Alternatively, you can click the button down below. help.description=Here is a list of what I can do help.buttonsToo=You can do the same operations you''d do with the commands aforementioned by selecting the corresponding button below \ud83d\udc47 help.cmdDescription=Print the help message +notfound.description=Mmm I''m not able to find command {0}, are you sure to have it typed correctly? +notfound.howToHelp=Let me show you what I can do by typing /help in the chat! diff --git a/src/main/resources/i18n/message_en_US.properties b/src/main/resources/i18n/message_en_US.properties index d022a29..f8458cd 100644 --- a/src/main/resources/i18n/message_en_US.properties +++ b/src/main/resources/i18n/message_en_US.properties @@ -10,6 +10,8 @@ changeLanguage.english=English changeLanguage.italian=Italian changeLanguage.cmdDescription=Select the new language I will use to speak to you changeLanguage.inlineKeyboardButtonName=Change language +selectLanguageTutorial.english=English +selectLanguageTutorial.italian=Italian spell.speakWithAnimals=Speak with animals selectLanguageTutorial.showMeTutorialInlineKeyboardButtonName=Show me what you can do! help.notShownYet=It seems you haven''t checked out what I can do yet! To have a complete list of my abilities, type /help in chat at any time! @@ -17,3 +19,5 @@ help.buttonBelow=Alternatively, you can click the button down below. help.description=Here is a list of what I can do help.buttonsToo=You can do the same operations you''d do with the commands aforementioned by selecting the corresponding button below \ud83d\udc47 help.cmdDescription=Print the help message +notfound.description=Mmm I''m not able to find command {0}, are you sure to have it typed correctly? +notfound.howToHelp=Let me show you what I can do by typing /help in the chat! diff --git a/src/main/resources/i18n/message_it.properties b/src/main/resources/i18n/message_it.properties index 01ae788..cc81ee8 100644 --- a/src/main/resources/i18n/message_it.properties +++ b/src/main/resources/i18n/message_it.properties @@ -1,11 +1,23 @@ start.helloFirstName=Ciao {0}! \ud83d\udc4b start.description=Questo è {0}, un semplice bot che ci concenta sulla gestione di contenuto per DnD! Per favore comincia selezionando la lingua qui sotto \ud83d\udc47 +start.cmdDescription=Comincia a chattare con questo bot +start.inlineKeyboardButtonName=Cominciamo! +selectLanguageTutorial.inlineKeyboardButtonName=Seleziona linguaggio selectLanguageTutorial.drinkAction=*Procede a bere una pozione al cui suo interno si trova uno strano liquido multicolore* selectLanguageTutorial.setLanguage=Grazie! Ora che ho bevuto questa posizione modificata di {0} che ho trovato ieri al negozio di pozioni magiche la "Cristalleria Fermentatrice" posso parlare con te nel linguaggio che preferisci! selectLanguageTutorial.instructions=Puoi sempre cambiare le preferenze della tua lingua scrivendo /changeLanguage nella chat. +changeLanguage.english=Inglese +changeLanguage.italian=Italiano +changeLanguage.cmdDescription=Seleziona il nuovo linguaggio che userò per parlare con te +changeLanguage.inlineKeyboardButtonName=Cambia lingua selectLanguageTutorial.english=Inglese selectLanguageTutorial.italian=Italiano spell.speakWithAnimals=Parlare con animali selectLanguageTutorial.showMeTutorialInlineKeyboardButtonName=Mostrami cosa puoi fare! help.notShownYet=Sembra tu non abbia ancora visto cosa posso fare! Per avere una lista completa delle mie abilità, scrivi /help nella chat in qualsiasi momento! help.buttonBelow=Alternativamente, puoi premere il bottone qui sotto. +help.description=Ecco una lista di quello che sono in grado di fare +help.buttonsToo=Puoi fare le stesse operazioni che faresti con i comandi elencati precedentemente cliccando il bottone corrispondente qui di sotto \ud83d\udc47 +help.cmdDescription=Stampa il messaggio d'aiuto +notfound.description=Mmm non sono in grado di trovare il comando {0}, sei sicuro di averlo scritto correttamente? +notfound.howToHelp=Lascia che ti mostri cosa posso fare, scrivi /help nella chat! diff --git a/src/main/resources/i18n/message_it_IT.properties b/src/main/resources/i18n/message_it_IT.properties index 01ae788..cc81ee8 100644 --- a/src/main/resources/i18n/message_it_IT.properties +++ b/src/main/resources/i18n/message_it_IT.properties @@ -1,11 +1,23 @@ start.helloFirstName=Ciao {0}! \ud83d\udc4b start.description=Questo è {0}, un semplice bot che ci concenta sulla gestione di contenuto per DnD! Per favore comincia selezionando la lingua qui sotto \ud83d\udc47 +start.cmdDescription=Comincia a chattare con questo bot +start.inlineKeyboardButtonName=Cominciamo! +selectLanguageTutorial.inlineKeyboardButtonName=Seleziona linguaggio selectLanguageTutorial.drinkAction=*Procede a bere una pozione al cui suo interno si trova uno strano liquido multicolore* selectLanguageTutorial.setLanguage=Grazie! Ora che ho bevuto questa posizione modificata di {0} che ho trovato ieri al negozio di pozioni magiche la "Cristalleria Fermentatrice" posso parlare con te nel linguaggio che preferisci! selectLanguageTutorial.instructions=Puoi sempre cambiare le preferenze della tua lingua scrivendo /changeLanguage nella chat. +changeLanguage.english=Inglese +changeLanguage.italian=Italiano +changeLanguage.cmdDescription=Seleziona il nuovo linguaggio che userò per parlare con te +changeLanguage.inlineKeyboardButtonName=Cambia lingua selectLanguageTutorial.english=Inglese selectLanguageTutorial.italian=Italiano spell.speakWithAnimals=Parlare con animali selectLanguageTutorial.showMeTutorialInlineKeyboardButtonName=Mostrami cosa puoi fare! help.notShownYet=Sembra tu non abbia ancora visto cosa posso fare! Per avere una lista completa delle mie abilità, scrivi /help nella chat in qualsiasi momento! help.buttonBelow=Alternativamente, puoi premere il bottone qui sotto. +help.description=Ecco una lista di quello che sono in grado di fare +help.buttonsToo=Puoi fare le stesse operazioni che faresti con i comandi elencati precedentemente cliccando il bottone corrispondente qui di sotto \ud83d\udc47 +help.cmdDescription=Stampa il messaggio d'aiuto +notfound.description=Mmm non sono in grado di trovare il comando {0}, sei sicuro di averlo scritto correttamente? +notfound.howToHelp=Lascia che ti mostri cosa posso fare, scrivi /help nella chat! diff --git a/src/main/resources/template/telegram/notFound.vm b/src/main/resources/template/telegram/notFound.vm new file mode 100644 index 0000000..18916a1 --- /dev/null +++ b/src/main/resources/template/telegram/notFound.vm @@ -0,0 +1,3 @@ +${i18n.notfound.description.insert(${cmdName})} + +${i18n.notfound.howToHelp} \ No newline at end of file diff --git a/src/test/java/com/github/polpetta/mezzotre/util/ServiceModuleTest.java b/src/test/java/com/github/polpetta/mezzotre/util/ServiceModuleTest.java new file mode 100644 index 0000000..a698b78 --- /dev/null +++ b/src/test/java/com/github/polpetta/mezzotre/util/ServiceModuleTest.java @@ -0,0 +1,72 @@ +package com.github.polpetta.mezzotre.util; + +import static org.junit.jupiter.api.Assertions.*; + +import com.google.common.util.concurrent.Service; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; + +@Execution(ExecutionMode.CONCURRENT) +class ServiceModuleTest { + + /** + * This test seems stupid, but it is actually important that the behavior of the extension is + * always with a {@code lateInit} set to true, otherwise services won't be alive for the whole JVM + * execution + */ + @Test + void shouldBeLateInit() { + // Necessary otherwise ServiceManager will throw exception in the constructor 🤦 + final Service dumbService = + new Service() { + @Override + public Service startAsync() { + return null; + } + + @Override + public boolean isRunning() { + return false; + } + + @Override + public State state() { + return State.NEW; + } + + @Override + public Service stopAsync() { + return null; + } + + @Override + public void awaitRunning() {} + + @Override + public void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException {} + + @Override + public void awaitTerminated() {} + + @Override + public void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException {} + + @Override + public Throwable failureCause() { + return null; + } + + @Override + public void addListener(Listener listener, Executor executor) {} + }; + + final ServiceModule serviceModule = new ServiceModule(List.of(dumbService)); + + assertTrue(serviceModule.lateinit()); + } +}