Skip to content

Commit

Permalink
Qute message bundles: change the way message templates are loaded
Browse files Browse the repository at this point in the history
- introduce a dedicated TemplateLocator so that the message templates
can be reloaded automatically when a no-restart change occurs during the
dev mode
- fixes quarkusio#43944

(cherry picked from commit af45546)
  • Loading branch information
mkouba authored and gsmet committed Oct 21, 2024
1 parent 2381b5e commit 77efb11
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.arc.processor.Annotations;
import io.quarkus.arc.processor.BeanInfo;
import io.quarkus.arc.processor.BuiltinScope;
import io.quarkus.arc.processor.DotNames;
import io.quarkus.deployment.ApplicationArchive;
import io.quarkus.deployment.GeneratedClassGizmoAdaptor;
Expand Down Expand Up @@ -98,6 +99,7 @@
import io.quarkus.qute.i18n.Message;
import io.quarkus.qute.i18n.MessageBundle;
import io.quarkus.qute.i18n.MessageBundles;
import io.quarkus.qute.i18n.MessageTemplateLocator;
import io.quarkus.qute.runtime.MessageBundleRecorder;
import io.quarkus.qute.runtime.QuteConfig;
import io.quarkus.runtime.LocalesBuildTimeConfig;
Expand All @@ -115,7 +117,8 @@ public class MessageBundleProcessor {

@BuildStep
AdditionalBeanBuildItem beans() {
return new AdditionalBeanBuildItem(MessageBundles.class, MessageBundle.class, Message.class, Localized.class);
return new AdditionalBeanBuildItem(MessageBundles.class, MessageBundle.class, Message.class, Localized.class,
MessageTemplateLocator.class);
}

@BuildStep
Expand Down Expand Up @@ -349,6 +352,10 @@ void initBundleContext(MessageBundleRecorder recorder,
List<MessageBundleBuildItem> bundles,
BuildProducer<SyntheticBeanBuildItem> syntheticBeans) throws ClassNotFoundException {

if (bundles.isEmpty()) {
return;
}

Map<String, Map<String, Class<?>>> bundleInterfaces = new HashMap<>();
for (MessageBundleBuildItem bundle : bundles) {
final Class<?> bundleClass = Class.forName(bundle.getDefaultBundleInterface().toString(), true,
Expand All @@ -372,7 +379,9 @@ void initBundleContext(MessageBundleRecorder recorder,
MessageBundleMethodBuildItem::getTemplate));

syntheticBeans.produce(SyntheticBeanBuildItem.configure(MessageBundleRecorder.BundleContext.class)
.supplier(recorder.createContext(templateIdToContent, bundleInterfaces)).done());
.scope(BuiltinScope.DEPENDENT.getInfo())
.supplier(recorder.createContext(templateIdToContent, bundleInterfaces))
.done());
}

@BuildStep
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public void testCheckedTemplate() {

@Test
public void testLocatorsAreRegisteredAsSingletons() {
assertEquals(4, locatorList.size());
assertEquals(5, locatorList.size());
}

@Singleton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
import jakarta.enterprise.inject.Default;
import jakarta.enterprise.inject.Instance;

import org.jboss.logging.Logger;

import io.quarkus.arc.Arc;
import io.quarkus.arc.ArcContainer;
import io.quarkus.arc.InstanceHandle;
Expand All @@ -31,8 +29,6 @@ public final class MessageBundles {
public static final String ATTRIBUTE_LOCALE = TemplateInstance.LOCALE;
public static final String DEFAULT_LOCALE = "<<default>>";

private static final Logger LOGGER = Logger.getLogger(MessageBundles.class);

private MessageBundles() {
}

Expand Down Expand Up @@ -62,11 +58,14 @@ public static <T> T get(Class<T> bundleInterface, Localized localized) {
.render());
}

static void setupNamespaceResolvers(@Observes EngineBuilder builder, BundleContext context) {
static void setupNamespaceResolvers(@Observes EngineBuilder builder, Instance<BundleContext> context) {
if (!context.isResolvable()) {
return;
}
// Avoid injecting "Instance<Object> instance" which prevents unused beans removal
ArcContainer container = Arc.container();
// For every bundle register a new resolver
for (Entry<String, Map<String, Class<?>>> entry : context.getBundleInterfaces().entrySet()) {
for (Entry<String, Map<String, Class<?>>> entry : context.get().getBundleInterfaces().entrySet()) {
final String bundleName = entry.getKey();
final Map<String, Resolver> interfaces = new HashMap<>();
Resolver resolver = null;
Expand Down Expand Up @@ -121,10 +120,15 @@ public String getNamespace() {
}
}

static void setupMessageTemplates(@Observes Engine engine, BundleContext context) {
for (Entry<String, String> entry : context.getMessageTemplates().entrySet()) {
LOGGER.debugf("Register template for message [%s]", entry.getKey());
engine.putTemplate(entry.getKey(), engine.parse(entry.getValue()));
static void preloadMessageTemplates(@Observes Engine engine, Instance<BundleContext> context) {
if (!context.isResolvable()) {
return;
}
for (String key : context.get().getMessageTemplates().keySet()) {
Template messageTemplate = engine.getTemplate(key);
if (messageTemplate == null) {
throw new IllegalStateException("Unable to preload message template: " + key);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.quarkus.qute.i18n;

import java.io.Reader;
import java.io.StringReader;
import java.util.Optional;

import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;

import io.quarkus.arc.WithCaching;
import io.quarkus.qute.TemplateLocator;
import io.quarkus.qute.Variant;
import io.quarkus.qute.runtime.MessageBundleRecorder.BundleContext;

@Singleton
public class MessageTemplateLocator implements TemplateLocator {

@WithCaching // BundleContext is dependent
@Inject
Instance<BundleContext> bundleContext;

@Override
public int getPriority() {
return DEFAULT_PRIORITY - 1;
}

@Override
public Optional<TemplateLocation> locate(String id) {
if (bundleContext.isResolvable()) {
String template = bundleContext.get().getMessageTemplates().get(id);
if (template != null) {
return Optional.of(new MessageTemplateLocation(template));
}
}
return Optional.empty();
}

static final class MessageTemplateLocation implements TemplateLocation {

private final String content;

private MessageTemplateLocation(String content) {
this.content = content;
}

@Override
public Reader read() {
return new StringReader(content);
}

@Override
public Optional<Variant> getVariant() {
return Optional.empty();
}

}

}

0 comments on commit 77efb11

Please sign in to comment.