Skip to content

Commit

Permalink
WFLY-1370 Allow CDI Extension to be loaded from static modules
Browse files Browse the repository at this point in the history
This commit changes the way CDI portable extensions are loaded,
so they will be picked up from any module that has its services
exposed to the deployment.

This will both allow users to register portable extensions from
static modules, and also allow subsystems to more easily register
extensions.
  • Loading branch information
stuartwdouglas authored and bstansberry committed May 23, 2013
1 parent 59ff359 commit e8ef344
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 179 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,12 @@
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
import org.jboss.as.web.common.WarMetaData;
import org.jboss.as.weld.WeldDeploymentMarker;
import org.jboss.as.weld.deployment.WeldAttachments;
import org.jboss.metadata.javaee.spec.ParamValueMetaData;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
import org.jboss.modules.Module;
import org.jboss.resteasy.cdi.ResteasyCdiExtension;
import org.jboss.weld.bootstrap.spi.Metadata;

import javax.enterprise.inject.spi.Extension;
import java.util.ArrayList;
import java.util.List;
import org.wildfly.security.manager.WildFlySecurityManager;

/**
* @author Stuart Douglas
Expand Down Expand Up @@ -74,42 +69,6 @@ public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentU
if (WeldDeploymentMarker.isPartOfWeldDeployment(deploymentUnit)) {
JAXRS_LOGGER.debug("Found CDI, adding injector factory class");
setContextParameter(webdata, "resteasy.injector.factory", CDI_INJECTOR_FACTORY_CLASS);
//now we need to add the CDI extension, if it has not
//already been added
synchronized (parent) {
boolean found = false;
final List<Metadata<Extension>> extensions = parent.getAttachmentList(WeldAttachments.PORTABLE_EXTENSIONS);
for (Metadata<Extension> extension : extensions) {
if (extension.getValue() instanceof ResteasyCdiExtension) {
found = true;
break;
}
}
if (!found) {

final ClassLoader classLoader = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged();
try {
//MASSIVE HACK
//the resteasy Logger throws a NPE if the TCCL is null
WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(ResteasyCdiExtension.class.getClassLoader());
final ResteasyCdiExtension ext = new ResteasyCdiExtension();
Metadata<Extension> metadata = new Metadata<Extension>() {
@Override
public Extension getValue() {
return ext;
}

@Override
public String getLocation() {
return "org.jboss.as.jaxrs.JaxrsExtension";
}
};
parent.addToAttachmentList(WeldAttachments.PORTABLE_EXTENSIONS, metadata);
} finally {
WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(classLoader);
}
}
}
}
} catch (ClassNotFoundException ignored) {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@
*/
package org.jboss.as.jsf.deployment;

import com.sun.faces.flow.FlowCDIExtension;
import com.sun.faces.flow.FlowDiscoveryCDIExtension;
import com.sun.faces.application.view.ViewScopeExtension;

import javax.enterprise.inject.spi.Extension;

import org.jboss.as.ee.structure.DeploymentType;
import org.jboss.as.ee.structure.DeploymentTypeMarker;
import org.jboss.as.jsf.JSFLogger;
Expand All @@ -38,13 +32,10 @@
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
import org.jboss.as.server.deployment.module.ModuleDependency;
import org.jboss.as.server.deployment.module.ModuleSpecification;
import org.jboss.as.weld.deployment.WeldAttachments;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoader;
import org.jboss.modules.filter.PathFilters;
import org.jboss.weld.bootstrap.spi.Metadata;
import org.wildfly.security.manager.WildFlySecurityManager;

/**
* @author Stan Silvert ssilvert@redhat.com (C) 2012 Red Hat Inc.
Expand Down Expand Up @@ -115,20 +106,9 @@ private void addJSFImpl(String jsfVersion,
if (jsfVersion.equals(JsfVersionMarker.WAR_BUNDLES_JSF_IMPL)) return;

ModuleIdentifier jsfModule = moduleIdFactory.getImplModId(jsfVersion);
ModuleDependency jsfImpl = new ModuleDependency(moduleLoader, jsfModule, false, false, false, false);
ModuleDependency jsfImpl = new ModuleDependency(moduleLoader, jsfModule, false, false, true, false);
jsfImpl.addImportFilter(PathFilters.getMetaInfFilter(), true);
moduleSpecification.addSystemDependency(jsfImpl);

// HACK!! Determine if we are using Mojarra 2.2 or greater
try {
jsfImpl.getModuleLoader().loadModule(jsfModule).getClassLoader().loadClass("com.sun.faces.flow.FlowCDIExtension");
} catch (Exception e) {
// If we can't load FlowCDIExtension then we must be using MyFaces or a pre-2.2 Mojarra impl.
return;
}

// If using Mojarra 2.2 or greater, enable CDI Extensions
addCDIExtensions(topLevelDeployment);
}

private void addJSFInjection(String jsfVersion, ModuleSpecification moduleSpecification, ModuleLoader moduleLoader) {
Expand All @@ -138,44 +118,4 @@ private void addJSFInjection(String jsfVersion, ModuleSpecification moduleSpecif
ModuleDependency jsfInjectionDependency = new ModuleDependency(moduleLoader, jsfInjectionModule, false, true, true, false);
moduleSpecification.addSystemDependency(jsfInjectionDependency);
}

// HACK!!! CDI Extensions should be automatically loaded from the Weld subsystem. For now, CDI Extensions are only
// recognized if the jar containing the service resides in the deployment. Since Weld subsystem doesn't handle this yet,
// we do it here.
private void addCDIExtensions(DeploymentUnit topLevelDeployment) {
final ClassLoader classLoader = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged();
try {
WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(FlowCDIExtension.class.getClassLoader());

Metadata<Extension> metadata = new CDIExtensionMetadataImpl(new FlowCDIExtension());
topLevelDeployment.addToAttachmentList(WeldAttachments.PORTABLE_EXTENSIONS, metadata);

metadata = new CDIExtensionMetadataImpl(new ViewScopeExtension());
topLevelDeployment.addToAttachmentList(WeldAttachments.PORTABLE_EXTENSIONS, metadata);

metadata = new CDIExtensionMetadataImpl(new FlowDiscoveryCDIExtension());
topLevelDeployment.addToAttachmentList(WeldAttachments.PORTABLE_EXTENSIONS, metadata);
} finally {
WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(classLoader);
}
}

private static class CDIExtensionMetadataImpl implements Metadata<Extension> {

private final Extension ext;

public CDIExtensionMetadataImpl(Extension ext) {
this.ext = ext;
}

@Override
public Extension getValue() {
return ext;
}

@Override
public String getLocation() {
return ext.getClass().getName();
}
}
}
4 changes: 2 additions & 2 deletions weld/src/main/java/org/jboss/as/weld/WeldMessages.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ public interface WeldMessages {
@Message(id= 16052, value = "Could not load interceptor class : %s")
DeploymentUnitProcessingException couldNotLoadInterceptorClass(String interceptorClass, @Cause Throwable cause);

@Message(id=16053, value = "Service class %s didn't implement the javax.enterprise.inject.spi.Extension interface")
DeploymentUnitProcessingException extensionDoesNotImplementExtension(String className, @Cause Throwable throwable);
@Message(id=16053, value = "Service %s didn't implement the javax.enterprise.inject.spi.Extension interface")
DeploymentUnitProcessingException extensionDoesNotImplementExtension(Class<?> clazz);

@Message(id = 16054, value = "View of type %s not found on EJB %s")
IllegalArgumentException viewNotFoundOnEJB(String viewType, String ejb);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@
*/
package org.jboss.as.weld.deployment;

import javax.enterprise.inject.spi.Extension;

import org.jboss.as.server.deployment.AttachmentKey;
import org.jboss.as.server.deployment.AttachmentList;
import org.jboss.weld.bootstrap.spi.Metadata;

/**
* {@link AttachmentKey}s for weld attachments
Expand Down Expand Up @@ -56,9 +54,4 @@ public class WeldAttachments {
*/
public static final AttachmentKey<BeanDeploymentArchiveImpl> DEPLOYMENT_ROOT_BEAN_DEPLOYMENT_ARCHIVE = AttachmentKey.create(BeanDeploymentArchiveImpl.class);

/**
* Portable extensions discovered in sub deployments. All sub deployments may contain portable extensions, even ones without
* beans.xml files
*/
public static final AttachmentKey<AttachmentList<Metadata<Extension>>> PORTABLE_EXTENSIONS = AttachmentKey.createList(Metadata.class);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.jboss.as.weld.deployment;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import javax.enterprise.inject.spi.Extension;

import org.jboss.as.server.deployment.AttachmentKey;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.weld.WeldLogger;
import org.jboss.as.weld.WeldMessages;
import org.jboss.weld.bootstrap.spi.Metadata;
import org.jboss.weld.metadata.MetadataImpl;

/**
* Container class that is attached to the top level deployment that holds all portable extension metadata.
* <p/>
* A portable extension may be available to multiple deployment class loaders, however for each PE we
* only want to register a single instance.
* <p/>
* This container provides a mechanism for making sure that only a single PE of a given type is registered.
*
* @author Stuart Douglas
*/
public class WeldPortableExtensions {

private static final AttachmentKey<WeldPortableExtensions> ATTACHMENT_KEY = AttachmentKey.create(WeldPortableExtensions.class);

public static WeldPortableExtensions getPortableExtensions(final DeploymentUnit deploymentUnit) {
if (deploymentUnit.getParent() == null) {
WeldPortableExtensions pes = deploymentUnit.getAttachment(WeldPortableExtensions.ATTACHMENT_KEY);
if (pes == null) {
deploymentUnit.putAttachment(ATTACHMENT_KEY, pes = new WeldPortableExtensions());
}
return pes;
} else {
return getPortableExtensions(deploymentUnit.getParent());
}
}

private final Map<Class<?>, Metadata<Extension>> extensions = new HashMap<>();

public synchronized void tryRegisterExtension(final Class<?> extensionClass, final DeploymentUnit deploymentUnit) throws DeploymentUnitProcessingException {
if (!Extension.class.isAssignableFrom(extensionClass)) {
throw WeldMessages.MESSAGES.extensionDoesNotImplementExtension(extensionClass);
}
if (extensions.containsKey(extensionClass)) {
return;
}
try {
extensions.put(extensionClass, new MetadataImpl<>((Extension) extensionClass.newInstance(), deploymentUnit.getName()));
} catch (InstantiationException e) {
WeldLogger.DEPLOYMENT_LOGGER.couldNotLoadPortableExceptionClass(extensionClass.getName(), e);
} catch (IllegalAccessException e) {
WeldLogger.DEPLOYMENT_LOGGER.couldNotLoadPortableExceptionClass(extensionClass.getName(), e);
}

}

public synchronized void registerExtensionInstance(final Extension extension, final DeploymentUnit deploymentUnit) {
extensions.put(extension.getClass(), new MetadataImpl<>(extension, deploymentUnit.getName()));
}

public Collection<Metadata<Extension>> getExtensions() {
return new HashSet<>(extensions.values());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
package org.jboss.as.weld.deployment.processors;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -64,6 +65,7 @@
import org.jboss.as.weld.deployment.CdiAnnotationMarker;
import org.jboss.as.weld.deployment.WeldAttachments;
import org.jboss.as.weld.deployment.WeldDeployment;
import org.jboss.as.weld.deployment.WeldPortableExtensions;
import org.jboss.as.weld.services.TCCLSingletonService;
import org.jboss.as.weld.services.bootstrap.WeldEjbInjectionServices;
import org.jboss.as.weld.services.bootstrap.WeldEjbServices;
Expand Down Expand Up @@ -215,7 +217,7 @@ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitPro
additional.addService(ResourceInjectionServices.class, resourceInjectionServices);
}

final List<Metadata<Extension>> extensions = deploymentUnit.getAttachmentList(WeldAttachments.PORTABLE_EXTENSIONS);
final Collection<Metadata<Extension>> extensions = WeldPortableExtensions.getPortableExtensions(deploymentUnit).getExtensions();

final WeldDeployment deployment = new WeldDeployment(beanDeploymentArchives, extensions, module, subDeploymentLoaders, deploymentUnit);

Expand Down
Loading

0 comments on commit e8ef344

Please sign in to comment.