From 4c73b514a759c72602e172b73d0c48366bdf95cd Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Wed, 24 Jul 2024 15:00:27 +0200 Subject: [PATCH] WFLY-19573 Expand WeldCapability to include build compatible extensions. Introduce separate WeldLogger entry for incorrect LiteExtensionTranslator setup. Change the CL and DU to that of a top level deployment when registering LiteExtensionTranslator. --- .../org/jboss/as/weld/WeldCapability.java | 19 ++++++++- .../deployment/WeldPortableExtensions.java | 41 +++++++++++++++++-- .../org/jboss/as/weld/logging/WeldLogger.java | 3 ++ .../org/jboss/as/weld/WeldCapabilityImpl.java | 9 ++++ .../processors/WeldDeploymentProcessor.java | 8 +++- .../WeldPortableExtensionProcessor.java | 12 ++---- 6 files changed, 76 insertions(+), 16 deletions(-) diff --git a/weld/common/src/main/java/org/jboss/as/weld/WeldCapability.java b/weld/common/src/main/java/org/jboss/as/weld/WeldCapability.java index b40831d7ab35..1464cbe1800c 100644 --- a/weld/common/src/main/java/org/jboss/as/weld/WeldCapability.java +++ b/weld/common/src/main/java/org/jboss/as/weld/WeldCapability.java @@ -6,6 +6,8 @@ package org.jboss.as.weld; import java.util.function.Supplier; + +import jakarta.enterprise.inject.build.compatible.spi.BuildCompatibleExtension; import jakarta.enterprise.inject.spi.BeanManager; import jakarta.enterprise.inject.spi.Extension; @@ -26,15 +28,28 @@ public interface WeldCapability { * Registers a CDI Portable Extension for the {@link DeploymentUnit} passed as argument to * this method. *

- * The extension is registered if only if the DeploymentUnit is part of a Weld Deployment. Specifically, + * The extension is registered if and only if the DeploymentUnit is part of a Weld Deployment. Specifically, * if a call to {@link #isPartOfWeldDeployment(DeploymentUnit)} using the DeploymentUnit argument - * returns {@code true}. Otherwise this method will return immediately. + * returns {@code true}. Otherwise, this method will return immediately. * * @param extension An instance of the CDI portable extension to add. * @param unit The deployment unit where the extension will be registered. */ void registerExtensionInstance(final Extension extension, final DeploymentUnit unit); + /** + * Registers a CDI Build Compatible Extension for the {@link DeploymentUnit} passed as argument to + * this method. + *

+ * The extension is registered if and only if the DeploymentUnit is part of a Weld Deployment. Specifically, + * if a call to {@link #isPartOfWeldDeployment(DeploymentUnit)} using the DeploymentUnit argument + * returns {@code true}. Otherwise, this method will return immediately. + * + * @param extension An instance of the CDI portable extension to add. + * @param unit The deployment unit where the extension will be registered. + */ + void registerBuildCompatibleExtension(final Class extension, final DeploymentUnit unit); + /** * Adds the Bean Manager service associated to the {@link DeploymentUnit} to ServiceBuilder passed as argument. *

diff --git a/weld/common/src/main/java/org/jboss/as/weld/deployment/WeldPortableExtensions.java b/weld/common/src/main/java/org/jboss/as/weld/deployment/WeldPortableExtensions.java index 4174c91c1086..e7be9fffcf38 100644 --- a/weld/common/src/main/java/org/jboss/as/weld/deployment/WeldPortableExtensions.java +++ b/weld/common/src/main/java/org/jboss/as/weld/deployment/WeldPortableExtensions.java @@ -5,11 +5,15 @@ package org.jboss.as.weld.deployment; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.function.Function; +import jakarta.enterprise.inject.build.compatible.spi.BuildCompatibleExtension; import jakarta.enterprise.inject.spi.Extension; import org.jboss.as.server.deployment.AttachmentKey; @@ -18,14 +22,16 @@ import org.jboss.as.weld.logging.WeldLogger; import org.jboss.weld.bootstrap.spi.Metadata; import org.jboss.weld.bootstrap.spi.helpers.MetadataImpl; +import org.jboss.weld.exceptions.IllegalArgumentException; /** - * Container class that is attached to the top level deployment that holds all portable extension metadata. + * Container class that is attached to the top level deployment that holds all portable and build compatible extensions + * metadata. *

- * A portable extension may be available to multiple deployment class loaders, however for each PE we + * A CDI extension may be available to multiple deployment class loaders, however for each PE we * only want to register a single instance. *

- * This container provides a mechanism for making sure that only a single PE of a given type is registered. + * This container provides a mechanism for making sure that only a single PE/BCE of a given type is registered. * * @author Stuart Douglas * @@ -52,6 +58,7 @@ public static WeldPortableExtensions getPortableExtensions(final DeploymentUnit } private final Map, Metadata> extensions = new HashMap<>(); + private final Collection> buildCompatibleExtensions = new ArrayList<>(); public synchronized void tryRegisterExtension(final Class extensionClass, final DeploymentUnit deploymentUnit) throws DeploymentUnitProcessingException { if (!Extension.class.isAssignableFrom(extensionClass)) { @@ -72,8 +79,36 @@ public synchronized void registerExtensionInstance(final Extension extension, fi extensions.put(extension.getClass(), new MetadataImpl<>(extension, deploymentUnit.getName())); } + public synchronized void registerBuildCompatibleExtension(final Class extension) { + buildCompatibleExtensions.add(extension); + } + + /** + * If there was at least one build compatible extension discovered or registered, this method will add a portable + * extension allowing their execution. It is a no-op if there are no build compatible extensions. + * + * @param extensionCreator a function that can create an instance of the {{@code LiteExtensionTranslator}} from given collection of found BCEs + * @throws IllegalArgumentException if the deployment unit parameter equals null + */ + public synchronized void registerLiteExtensionTranslatorIfNeeded(Function>, + Extension> extensionCreator, DeploymentUnit deploymentUnit) throws IllegalArgumentException { + if (deploymentUnit == null) { + throw WeldLogger.ROOT_LOGGER.incorrectBceTranslatorSetup(); + } + + // only register if we found any BCE be it via discovery or manual registration + if (!buildCompatibleExtensions.isEmpty()) { + registerExtensionInstance(extensionCreator.apply(getBuildCompatibleExtensions()), deploymentUnit); + } + } + public Collection> getExtensions() { return new HashSet<>(extensions.values()); } + public List> getBuildCompatibleExtensions() { + return new ArrayList<>(buildCompatibleExtensions); + } + + } diff --git a/weld/common/src/main/java/org/jboss/as/weld/logging/WeldLogger.java b/weld/common/src/main/java/org/jboss/as/weld/logging/WeldLogger.java index e5e8a254bbb5..cedff39b688c 100644 --- a/weld/common/src/main/java/org/jboss/as/weld/logging/WeldLogger.java +++ b/weld/common/src/main/java/org/jboss/as/weld/logging/WeldLogger.java @@ -267,4 +267,7 @@ public interface WeldLogger extends BasicLogger { @Message(id = 63, value = "Original %s does not have a module") IllegalArgumentException originalClassDoesNotHaveAModule(Class originalClass); + + @Message(id = 64, value = "Incorrect setup for Weld's LiteExtensionTranslator initialization; a deployment unit has to be specified") + IllegalArgumentException incorrectBceTranslatorSetup(); } diff --git a/weld/subsystem/src/main/java/org/jboss/as/weld/WeldCapabilityImpl.java b/weld/subsystem/src/main/java/org/jboss/as/weld/WeldCapabilityImpl.java index 9e96f6568d81..f598c5d94897 100644 --- a/weld/subsystem/src/main/java/org/jboss/as/weld/WeldCapabilityImpl.java +++ b/weld/subsystem/src/main/java/org/jboss/as/weld/WeldCapabilityImpl.java @@ -6,6 +6,7 @@ import java.util.function.Supplier; +import jakarta.enterprise.inject.build.compatible.spi.BuildCompatibleExtension; import jakarta.enterprise.inject.spi.BeanManager; import jakarta.enterprise.inject.spi.Extension; @@ -33,6 +34,14 @@ public void registerExtensionInstance(final Extension extension, final Deploymen } } + @Override + public void registerBuildCompatibleExtension(Class extension, DeploymentUnit unit) { + if (isPartOfWeldDeployment(unit)) { + WeldPortableExtensions extensions = WeldPortableExtensions.getPortableExtensions(unit); + extensions.registerBuildCompatibleExtension(extension); + } + } + @Override public Supplier addBeanManagerService(final DeploymentUnit unit, final ServiceBuilder serviceBuilder) { if (isPartOfWeldDeployment(unit)) { diff --git a/weld/subsystem/src/main/java/org/jboss/as/weld/deployment/processors/WeldDeploymentProcessor.java b/weld/subsystem/src/main/java/org/jboss/as/weld/deployment/processors/WeldDeploymentProcessor.java index 8660dd84d4f1..051b1d176034 100644 --- a/weld/subsystem/src/main/java/org/jboss/as/weld/deployment/processors/WeldDeploymentProcessor.java +++ b/weld/subsystem/src/main/java/org/jboss/as/weld/deployment/processors/WeldDeploymentProcessor.java @@ -70,6 +70,7 @@ import org.jboss.weld.config.ConfigurationKey; import org.jboss.weld.configuration.spi.ExternalConfiguration; import org.jboss.weld.configuration.spi.helpers.ExternalConfigurationBuilder; +import org.jboss.weld.lite.extension.translator.LiteExtensionTranslator; import org.jboss.weld.manager.api.ExecutorServices; import org.jboss.weld.security.spi.SecurityServices; import org.jboss.weld.transaction.spi.TransactionServices; @@ -213,8 +214,11 @@ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitPro additional.getServices().add(entry.getKey(), Reflections.cast(entry.getValue())); } } - - final Collection> extensions = WeldPortableExtensions.getPortableExtensions(deploymentUnit).getExtensions(); + WeldPortableExtensions portableExtensions = WeldPortableExtensions.getPortableExtensions(deploymentUnit); + // register LiteExtensionTranslator as the last extension so that we have all info on registered BCEs + // NOTE: I chose to register it under the dep. unit of the top level deployment, using its CL, not sure if this is correct + portableExtensions.registerLiteExtensionTranslatorIfNeeded(classes -> new LiteExtensionTranslator(classes, module.getClassLoader()), deploymentUnit); + final Collection> extensions = portableExtensions.getExtensions(); final WeldDeployment deployment = new WeldDeployment(beanDeploymentArchives, extensions, module, subDeploymentLoaders, deploymentUnit, rootBeanDeploymentModule, eeModuleDescriptors); diff --git a/weld/subsystem/src/main/java/org/jboss/as/weld/deployment/processors/WeldPortableExtensionProcessor.java b/weld/subsystem/src/main/java/org/jboss/as/weld/deployment/processors/WeldPortableExtensionProcessor.java index 37f455758e46..ea68bbe25f40 100644 --- a/weld/subsystem/src/main/java/org/jboss/as/weld/deployment/processors/WeldPortableExtensionProcessor.java +++ b/weld/subsystem/src/main/java/org/jboss/as/weld/deployment/processors/WeldPortableExtensionProcessor.java @@ -28,7 +28,6 @@ import org.jboss.as.weld.logging.WeldLogger; import org.jboss.modules.Module; import org.jboss.vfs.VFSUtils; -import org.jboss.weld.lite.extension.translator.LiteExtensionTranslator; import org.wildfly.security.manager.WildFlySecurityManager; /** @@ -74,14 +73,9 @@ private void loadAttachments(Module module, DeploymentUnit deploymentUnit, WeldP // load class and register for portable extensions Collection> loadedPortableExtensions = loadExtensions(module, portableExtensionServices, Object.class); registerPortableExtensions(deploymentUnit, extensions, loadedPortableExtensions); - // load class and register for portable extensions - // if there is at least one, add a portable extension processing them - List> loadedBuildCompatExtensions = - loadExtensions(module, buildCompatibleExtensionServices, BuildCompatibleExtension.class); - if (!loadedBuildCompatExtensions.isEmpty()) { - Extension extension = new LiteExtensionTranslator(loadedBuildCompatExtensions, module.getClassLoader()); - // NOTE: I chose to register it under the same dep. unit as other extensions, not sure if this is correct - extensions.registerExtensionInstance(extension, deploymentUnit); + // load class and register for discovered build compatible extensions + for (Class extensionClass : loadExtensions(module, buildCompatibleExtensionServices, BuildCompatibleExtension.class)) { + extensions.registerBuildCompatibleExtension(extensionClass); } } catch (IOException e) { throw new DeploymentUnitProcessingException(e);