Skip to content

Commit

Permalink
Greatly simplify TemplateInstance passing of locale and renderArgs
Browse files Browse the repository at this point in the history
Fixes localisation via type-safe messages for emails
  • Loading branch information
FroMage committed Nov 9, 2023
1 parent b096fbd commit 6113722
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 114 deletions.
5 changes: 5 additions & 0 deletions deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-mailer</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package io.quarkiverse.renarde.deployment;

import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.COMPLETION_STAGE;
import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.UNI;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
Expand All @@ -18,7 +15,6 @@
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
Expand Down Expand Up @@ -49,17 +45,13 @@
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.ParameterizedType;
import org.jboss.jandex.Type;
import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames;
import org.jboss.resteasy.reactive.common.processor.transformation.AnnotationsTransformer;
import org.jboss.resteasy.reactive.common.processor.transformation.AnnotationsTransformer.TransformationContext;
import org.jboss.resteasy.reactive.common.processor.transformation.Transformation;
import org.jboss.resteasy.reactive.common.util.URLUtils;
import org.jboss.resteasy.reactive.server.model.FixedHandlersChainCustomizer;
import org.jboss.resteasy.reactive.server.model.HandlerChainCustomizer;
import org.jboss.resteasy.reactive.server.processor.scanning.MethodScanner;

import io.quarkiverse.renarde.Controller;
import io.quarkiverse.renarde.deployment.ControllerVisitor.ControllerClass;
Expand All @@ -83,7 +75,6 @@
import io.quarkiverse.renarde.util.RenardeJWTAuthMechanism;
import io.quarkiverse.renarde.util.RenardeValidationLocaleResolver;
import io.quarkiverse.renarde.util.RenderArgs;
import io.quarkiverse.renarde.util.TemplateResponseHandler;
import io.quarkiverse.renarde.util.Validation;
import io.quarkus.arc.Unremovable;
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
Expand Down Expand Up @@ -132,7 +123,6 @@
import io.quarkus.hibernate.validator.runtime.jaxrs.ResteasyReactiveEndPointValidationInterceptor;
import io.quarkus.qute.TemplateInstance;
import io.quarkus.resteasy.reactive.server.spi.AnnotationsTransformerBuildItem;
import io.quarkus.resteasy.reactive.server.spi.MethodScannerBuildItem;
import io.quarkus.resteasy.reactive.spi.AdditionalResourceClassBuildItem;
import io.quarkus.resteasy.reactive.spi.CustomExceptionMapperBuildItem;
import io.quarkus.resteasy.reactive.spi.ParamConverterBuildItem;
Expand Down Expand Up @@ -882,38 +872,4 @@ void findMessageFiles(RenardeRecorder recorder,
logger.infof("Supported locales with messages: %s", languageToPath.keySet());
}
}

@BuildStep
public MethodScannerBuildItem configureHandler() {
// we register a scanner that runs in the first phase, to be before Qute's TemplateResponseUniHandler
// which means we run the risk of not having any Uni or CompletionStage unpacked yet, but that's fine
// we will hook into them
return new MethodScannerBuildItem(new MethodScanner() {
@Override
public List<HandlerChainCustomizer> scan(MethodInfo method, ClassInfo actualEndpointClass,
Map<String, Object> methodContext) {
if (method.returnType().name().equals(DOTNAME_TEMPLATE_INSTANCE)
|| isAsyncTemplateInstance(method.returnType())) {
return Collections.singletonList(
new FixedHandlersChainCustomizer(
List.of(new TemplateResponseHandler()),
HandlerChainCustomizer.Phase.AFTER_METHOD_INVOKE));
}
return Collections.emptyList();
}

private boolean isAsyncTemplateInstance(Type type) {
boolean isAsyncTemplateInstance = false;
if (type.kind() == Type.Kind.PARAMETERIZED_TYPE) {
ParameterizedType parameterizedType = type.asParameterizedType();
if ((parameterizedType.name().equals(UNI) || parameterizedType.name().equals(COMPLETION_STAGE))
&& (parameterizedType.arguments().size() == 1)) {
DotName firstParameterType = parameterizedType.arguments().get(0).name();
isAsyncTemplateInstance = firstParameterType.equals(DOTNAME_TEMPLATE_INSTANCE);
}
}
return isAsyncTemplateInstance;
}
});
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package io.quarkiverse.renarde.test;

import java.net.URL;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

import jakarta.inject.Inject;
import jakarta.validation.constraints.NotEmpty;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
Expand All @@ -16,11 +18,15 @@
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkiverse.renarde.Controller;
import io.quarkiverse.renarde.util.I18N;
import io.quarkus.mailer.Mail;
import io.quarkus.mailer.MailTemplate.MailTemplateInstance;
import io.quarkus.mailer.MockMailbox;
import io.quarkus.qute.CheckedTemplate;
import io.quarkus.qute.TemplateInstance;
import io.quarkus.qute.i18n.Message;
Expand Down Expand Up @@ -67,6 +73,9 @@ public class LanguageTest {
+ "{m:my.params('STEF')}\n"
+ "{m:missing}"),
"templates/MyController/typeUnsafe.txt")
.addAsResource(new StringAsset("{m:my_greeting}\n"
+ "{msg:my_greeting}"),
"templates/MyController/mail.txt")

.addAsResource(new StringAsset("quarkus.locales=en,fr\n"
+ "quarkus.default-locale=en"), "application.properties")
Expand All @@ -75,6 +84,9 @@ public class LanguageTest {
@TestHTTPResource
URL url;

@Inject
MockMailbox mailbox;

@Test
public void testDefaultLanguage() {
RestAssured
Expand Down Expand Up @@ -197,6 +209,30 @@ public void testTypeUnsafeLanguage() {
.statusCode(500);
}

@Test
public void testMail() {
mailbox.clear();
RestAssured
.get("/mail").then()
.statusCode(200)
.body(Matchers.is("OK"));
List<Mail> mails = mailbox.getMailsSentTo("[email protected]");
Assertions.assertEquals(1, mails.size());
Assertions.assertEquals("english message\nenglish message", mails.get(0).getText());

mailbox.clear();
RestAssured
.given()
.cookie(I18N.LOCALE_COOKIE_NAME, "fr")
.get("/mail").then()
.statusCode(200)
.body(Matchers.is("OK"));

mails = mailbox.getMailsSentTo("[email protected]");
Assertions.assertEquals(1, mails.size());
Assertions.assertEquals("message français\nmessage français", mails.get(0).getText());
}

@Test
public void testValidationLanguage() {
RestAssured
Expand All @@ -220,6 +256,8 @@ public static class Templates {
public static native TemplateInstance qute();

public static native TemplateInstance typeUnsafe(Object val);

public static native MailTemplateInstance mail();
}

@Path("/qute")
Expand Down Expand Up @@ -258,6 +296,12 @@ public String validation(@NotEmpty @RestForm String param) {
return validation.getError("param");
}

@Path("/mail")
public String mail() {
Templates.mail().to("[email protected]").send().await().indefinitely();
return "OK";
}

@Path("/lang")
public String lang() {
return i18n.getLanguage();
Expand Down
23 changes: 0 additions & 23 deletions runtime/src/main/java/io/quarkiverse/renarde/util/Filters.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package io.quarkiverse.renarde.util;

import java.util.Map.Entry;

import jakarta.inject.Inject;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.container.ContainerResponseContext;
Expand All @@ -10,16 +8,11 @@
import org.jboss.resteasy.reactive.server.ServerResponseFilter;
import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerRequestContext;

import io.quarkus.qute.TemplateInstance;
import io.quarkus.qute.i18n.MessageBundles;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;

public class Filters {

@Inject
RenderArgs renderArgs;

@Inject
Flash flash;

Expand All @@ -35,23 +28,7 @@ public void filterRequest(ResteasyReactiveContainerRequestContext requestContext
// this must run before the Qute response filter
@ServerResponseFilter(priority = Priorities.USER + 1000) // sorted in reverse order
public void filterResponse(ContainerResponseContext responseContext, HttpServerResponse resp) {
Object entity = responseContext.getEntity();
// this pass only handles methods that return Response or RestResponse, the others are handled in TemplateResponseHandler
if (entity instanceof TemplateInstance) {
TemplateInstance template = (TemplateInstance) entity;
setTemplateLocaleAndRenderArgs(template);
}
i18n.setLanguageCookie();
flash.setFlashCookie();
}

void setTemplateLocaleAndRenderArgs(TemplateInstance template) {
// extra parameters
for (Entry<String, Object> entry : renderArgs.entrySet()) {
template.data(entry.getKey(), entry.getValue());
}
// set the proper locale
template.setAttribute(MessageBundles.ATTRIBUTE_LOCALE, i18n.getLanguage());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.CompletionStage;
import java.util.function.BiFunction;

Expand All @@ -17,6 +18,7 @@
import io.quarkus.qute.Expression;
import io.quarkus.qute.NamespaceResolver;
import io.quarkus.qute.ValueResolver;
import io.quarkus.qute.i18n.MessageBundles;
import io.smallrye.mutiny.Uni;

public class QuteResolvers {
Expand Down Expand Up @@ -128,6 +130,22 @@ void configureEngine(@Observes EngineBuilder builder) {
.build());
}

void registerTemplateInstanceLocaleAndRenderArgs(@Observes EngineBuilder engineBuilder, I18N i18n, RenderArgs renderArgs) {
engineBuilder.addTemplateInstanceInitializer(templateInstance -> {
// This should work if `I18N` is a request scoped bean
if (Arc.container().requestContext().isActive()) {
if (i18n.getLocale() != null
&& templateInstance.getAttribute(MessageBundles.ATTRIBUTE_LOCALE) == null) {
templateInstance.setAttribute(MessageBundles.ATTRIBUTE_LOCALE, i18n.getLocale());
}
// extra parameters
for (Entry<String, Object> entry : renderArgs.entrySet()) {
templateInstance.data(entry.getKey(), entry.getValue());
}
}
});
}

private URI findURI(EvalContext ctx, List<?> paramValues) {
BoundRouter boundRouter = (BoundRouter) ctx.getBase();
// FIXME: make it work for multiple sets of parameters? with optional query params that's a bit harder
Expand Down

This file was deleted.

0 comments on commit 6113722

Please sign in to comment.