Skip to content

Commit

Permalink
Merge pull request wildfly#18295 from pferraro/WFLY-19806
Browse files Browse the repository at this point in the history
WFLY-19806 Restore singleton MDBs to working state (Take II)
  • Loading branch information
bstansberry authored Oct 15, 2024
2 parents ee5ce21 + b5b91c8 commit a24b44c
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
Expand All @@ -29,6 +30,7 @@
*/
public class DistributedSingletonServiceBuilder<T> extends AbstractSingletonServiceBuilder<T> {

private final ServiceName id = ServiceName.parse(UUID.randomUUID().toString());
private final Function<ServiceTarget, ServiceBuilder<?>> builderFactory;
private final List<Map.Entry<ServiceName[], Consumer<Consumer<?>>>> injectors = new LinkedList<>();
private final SingletonServiceBuilderContext context;
Expand All @@ -39,7 +41,8 @@ public DistributedSingletonServiceBuilder(ServiceBuilder<T> builder, Function<Se
super(new AsyncServiceBuilder<>(builder, builder.requires(ServiceName.parse("org.wildfly.management.executor"))), context);
this.builderFactory = builderFactory;
this.context = context;
this.singleton = singletonFactory.apply(builder).andThen(this.reference);
Consumer<Singleton> injector = builder.provides(this.id);
this.singleton = singletonFactory.apply(builder).andThen(this.reference).andThen(injector);
}

@SuppressWarnings("unchecked")
Expand All @@ -59,17 +62,14 @@ public void accept(V value) {

@Override
public SingletonServiceBuilder<T> setInstance(Service service) {
this.context.setServiceName(ServiceName.parse(service.getClass().getName()));
this.context.setService(service);
return this;
}

@Override
public SingletonServiceController<T> install() {
ServiceName name = this.context.getServiceName();
if (name == null) {
throw new IllegalStateException();
}
// Identify singleton service via its id if caller did not provide one
this.context.setServiceName(this.id);
ServiceController<T> controller = this.getDelegate().setInstance(new DistributedSingletonService(this.context, this.builderFactory, this.injectors, this.singleton)).install();
return new DistributedSingletonServiceController<>(controller, this.reference);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

package org.jboss.as.ejb3.component.messagedriven;

import org.jboss.msc.service.Service;
import java.util.function.Supplier;

import org.jboss.msc.Service;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.msc.value.InjectedValue;

/**
* Service that controls delivery for a specific MDB.
Expand All @@ -18,23 +18,21 @@
*
* @author Flavia Rainone
*/
public class MdbDeliveryControllerService implements Service<MdbDeliveryControllerService> {

private final InjectedValue<MessageDrivenComponent> mdbComponent = new InjectedValue<MessageDrivenComponent>();
public class MdbDeliveryControllerService implements Service {

public MdbDeliveryControllerService getValue() throws IllegalStateException, IllegalArgumentException {
return this;
}
private final Supplier<MessageDrivenComponent> mdbComponent;

public InjectedValue<MessageDrivenComponent> getMdbComponent() {
return mdbComponent;
public MdbDeliveryControllerService(Supplier<MessageDrivenComponent> mdbComponent) {
this.mdbComponent = mdbComponent;
}

public void start(final StartContext context) throws StartException {
mdbComponent.getValue().startDelivery();
@Override
public void start(StartContext context) {
this.mdbComponent.get().startDelivery();
}

public void stop(final StopContext context) {
mdbComponent.getValue().stopDelivery();
@Override
public void stop(StopContext context) {
mdbComponent.get().stopDelivery();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@

package org.jboss.as.ejb3.deployment.processors;

import static org.jboss.as.ee.component.Attachments.EE_MODULE_CONFIGURATION;
import static org.jboss.as.ejb3.subsystem.EJB3SubsystemRootResourceDefinition.CLUSTERED_SINGLETON;
import static org.jboss.as.ejb3.subsystem.EJB3SubsystemRootResourceDefinition.CLUSTERED_SINGLETON_BARRIER;
import static org.jboss.as.ejb3.subsystem.MdbDeliveryGroupResourceDefinition.MDB_DELIVERY_GROUP;

import org.jboss.as.controller.capability.CapabilityServiceSupport;
import org.jboss.as.ee.component.ComponentConfiguration;
import org.jboss.as.ee.component.ComponentDescription;
Expand All @@ -18,15 +23,12 @@
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceController.Mode;
import org.wildfly.clustering.singleton.service.ServiceTargetFactory;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.ServiceRegistry;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceTarget;
import org.wildfly.subsystem.service.ServiceDependency;
import org.wildfly.subsystem.service.ServiceInstaller;

import static org.jboss.as.ee.component.Attachments.EE_MODULE_CONFIGURATION;
import static org.jboss.as.ejb3.subsystem.EJB3SubsystemRootResourceDefinition.CLUSTERED_SINGLETON_CAPABILITY;
import static org.jboss.as.ejb3.subsystem.MdbDeliveryGroupResourceDefinition.MDB_DELIVERY_GROUP_CAPABILITY_NAME;
import java.util.function.Supplier;

/**
* MdbDeliveryDependencies DUP, creates an MdbDeliveryControllerService to enable/disable delivery according to that MDBs
Expand All @@ -53,50 +55,34 @@ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitPro
if (description instanceof MessageDrivenComponentDescription) {
final MessageDrivenComponentDescription mdbDescription = (MessageDrivenComponentDescription) description;
if (mdbDescription.isDeliveryControlled()) {
final MdbDeliveryControllerService mdbDeliveryControllerService = new MdbDeliveryControllerService();
final ServiceBuilder<MdbDeliveryControllerService> builder = serviceTarget.addService(mdbDescription.getDeliveryControllerName(), mdbDeliveryControllerService)
.addDependency(description.getCreateServiceName(), MessageDrivenComponent.class, mdbDeliveryControllerService.getMdbComponent())
.setInitialMode(Mode.PASSIVE);
// Use of named service is required by MessageDrivenBeanRuntimeHandler
ServiceBuilder<?> builder = serviceTarget.addService(mdbDescription.getDeliveryControllerName());

if (mdbDescription.isClusteredSingleton()) {
clusteredSingletonFound = true;
builder.requires(CLUSTERED_SINGLETON_CAPABILITY.getCapabilityServiceName());
// Require clustered singleton
builder.requires(capabilityServiceSupport.getCapabilityServiceName(CLUSTERED_SINGLETON));
}

if (mdbDescription.getDeliveryGroups() != null) {
for (String deliveryGroup : mdbDescription.getDeliveryGroups()) {
final ServiceName deliveryGroupServiceName = capabilityServiceSupport.getCapabilityServiceName(MDB_DELIVERY_GROUP_CAPABILITY_NAME, deliveryGroup);
if (phaseContext.getServiceRegistry().getService(deliveryGroupServiceName) == null) {
if (!capabilityServiceSupport.hasCapability(MDB_DELIVERY_GROUP, deliveryGroup)) {
throw EjbLogger.DEPLOYMENT_LOGGER.missingMdbDeliveryGroup(deliveryGroup);
}
builder.requires(deliveryGroupServiceName);
builder.requires(capabilityServiceSupport.getCapabilityServiceName(MDB_DELIVERY_GROUP, deliveryGroup));
}
}
builder.install();

Supplier<MessageDrivenComponent> component = builder.requires(description.getCreateServiceName());
builder.setInstance(new MdbDeliveryControllerService(component))
.setInitialMode(ServiceController.Mode.PASSIVE)
.install();
}
}
}
if (clusteredSingletonFound) {
// Add dependency on the default policy, which allows CLUSTERED_SINGLETON_CAPABILITY to be installed
serviceTarget.addDependency(capabilityServiceSupport.getCapabilityServiceName(ServiceTargetFactory.DEFAULT_SERVICE_DESCRIPTOR));
}
}

@Override
public void undeploy(DeploymentUnit deploymentUnit) {
final EEModuleConfiguration moduleConfiguration = deploymentUnit.getAttachment(EE_MODULE_CONFIGURATION);
if (moduleConfiguration == null) {
return;
}
final ServiceRegistry serviceRegistry = deploymentUnit.getServiceRegistry();
boolean clusteredSingletonFound = false;
for (final ComponentConfiguration configuration : moduleConfiguration.getComponentConfigurations()) {
final ComponentDescription description = configuration.getComponentDescription();
if (description instanceof MessageDrivenComponentDescription) {
MessageDrivenComponentDescription mdbDescription = (MessageDrivenComponentDescription) description;
clusteredSingletonFound = clusteredSingletonFound || mdbDescription.isClusteredSingleton();
if (mdbDescription.isDeliveryControlled()) {
serviceRegistry.getRequiredService(mdbDescription.getDeliveryControllerName()).setMode(Mode.REMOVE);
}
}
// Ensure singleton barrier is started
ServiceInstaller.builder(Boolean.TRUE).requires(ServiceDependency.on(CLUSTERED_SINGLETON_BARRIER)).build().install(phaseContext);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import static org.jboss.as.ejb3.subsystem.EJB3SubsystemModel.DEFAULT_SLSB_INSTANCE_POOL;
import static org.jboss.as.ejb3.subsystem.EJB3SubsystemModel.DEFAULT_STATEFUL_BEAN_ACCESS_TIMEOUT;
import static org.jboss.as.ejb3.subsystem.EJB3SubsystemModel.SERVER_INTERCEPTORS;
import static org.jboss.as.ejb3.subsystem.EJB3SubsystemRootResourceDefinition.CLUSTERED_SINGLETON_BARRIER;
import static org.jboss.as.ejb3.subsystem.EJB3SubsystemRootResourceDefinition.CLUSTERED_SINGLETON_CAPABILITY;
import static org.jboss.as.ejb3.subsystem.EJB3SubsystemRootResourceDefinition.DEFAULT_CLUSTERED_SFSB_CACHE;
import static org.jboss.as.ejb3.subsystem.EJB3SubsystemRootResourceDefinition.DEFAULT_MDB_POOL_CONFIG_CAPABILITY;
Expand All @@ -31,6 +32,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import javax.naming.NamingException;

Expand Down Expand Up @@ -149,6 +151,7 @@
import org.omg.PortableServer.POA;
import org.wildfly.clustering.server.registry.Registry;
import org.wildfly.clustering.singleton.service.ServiceTargetFactory;
import org.wildfly.common.function.Functions;
import org.wildfly.iiop.openjdk.rmi.DelegatingStubFactoryFactory;
import org.wildfly.iiop.openjdk.service.CorbaPOAService;
import org.wildfly.subsystem.service.ServiceDependency;
Expand Down Expand Up @@ -594,13 +597,25 @@ private static void addClusteringServices(final OperationContext context, final
ServiceInstaller installer = new ServiceInstaller() {
@Override
public ServiceController<?> install(RequirementServiceTarget target) {
ServiceBuilder<?> builder = targetFactory.get().createSingletonServiceTarget(target).addService();
return builder.setInstance(org.jboss.msc.Service.newInstance(builder.provides(CLUSTERED_SINGLETON_CAPABILITY.getCapabilityServiceName()), Boolean.TRUE))
.setInitialMode(ServiceController.Mode.ON_DEMAND)
.install();
// Install on-demand singleton service
// We don't want this to start until a deployment requires it
ServiceController<?> controller = org.wildfly.service.ServiceInstaller.builder(Functions.constantSupplier(Boolean.TRUE))
.provides(CLUSTERED_SINGLETON_CAPABILITY.getCapabilityServiceName())
.build()
.install(targetFactory.get().createSingletonServiceTarget(target));

// Install well-known on-demand service that, once started, will force singleton service instrumentation to start.
ServiceInstaller.builder(Functions.constantSupplier(Boolean.TRUE))
.provides(ServiceNameFactory.resolveServiceName(CLUSTERED_SINGLETON_BARRIER))
// N.B. Depend on ServiceName(s) provided by singleton service instrumentation
.requires(controller.provides().stream().map(ServiceDependency::on).collect(Collectors.toList()))
.build()
.install(target);

return controller;
}
};
ServiceInstaller.builder(installer, context.getCapabilityServiceSupport()).requires(targetFactory).asPassive().build().install(context);
ServiceInstaller.builder(installer, context.getCapabilityServiceSupport()).requires(targetFactory).build().install(context);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.jboss.as.threads.ThreadsServices;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import org.wildfly.service.descriptor.NullaryServiceDescriptor;

/**
* {@link org.jboss.as.controller.ResourceDefinition} for the EJB3 subsystem's root management resource.
Expand All @@ -69,7 +70,6 @@ public class EJB3SubsystemRootResourceDefinition extends SimpleResourceDefinitio

private static final String EJB_CAPABILITY_NAME = "org.wildfly.ejb3";
private static final String EJB_CLIENT_CONFIGURATOR_CAPABILITY_NAME = "org.wildfly.ejb3.remote.client-configurator";
private static final String CLUSTERED_SINGLETON_CAPABILITY_NAME = "org.wildfly.ejb3.clustered.singleton";
private static final String TRANSACTION_GLOBAL_DEFAULT_LOCAL_PROVIDER_CAPABILITY_NAME = "org.wildfly.transactions.global-default-local-provider";

static final SimpleAttributeDefinition DEFAULT_SLSB_INSTANCE_POOL =
Expand Down Expand Up @@ -230,8 +230,9 @@ public class EJB3SubsystemRootResourceDefinition extends SimpleResourceDefinitio
.setMaxSize(Integer.MAX_VALUE)
.build();

public static final RuntimeCapability<Void> CLUSTERED_SINGLETON_CAPABILITY = RuntimeCapability.Builder.of(
CLUSTERED_SINGLETON_CAPABILITY_NAME, Void.class).build();
public static final NullaryServiceDescriptor<Void> CLUSTERED_SINGLETON_BARRIER = NullaryServiceDescriptor.of("org.wildfly.ejb3.clustered.singleton.barrier", Void.class);
public static final NullaryServiceDescriptor<Void> CLUSTERED_SINGLETON = NullaryServiceDescriptor.of("org.wildfly.ejb3.clustered.singleton", Void.class);
static final RuntimeCapability<Void> CLUSTERED_SINGLETON_CAPABILITY = RuntimeCapability.Builder.of(CLUSTERED_SINGLETON).build();

public static final RuntimeCapability<Void> EJB_CAPABILITY = RuntimeCapability.Builder.of(EJB_CAPABILITY_NAME, Void.class)
// EJBComponentDescription adds a create dependency on the local tx provider to all components,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@
*/
public class MdbDeliveryGroupAdd extends AbstractAddStepHandler {

static final MdbDeliveryGroupAdd INSTANCE = new MdbDeliveryGroupAdd();

private MdbDeliveryGroupAdd() {
super(MdbDeliveryGroupResourceDefinition.ACTIVE);
}

@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
installServices(context, operation, model);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import org.jboss.msc.Service;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceName;
import org.wildfly.service.descriptor.UnaryServiceDescriptor;

/**
* {@link org.jboss.as.controller.ResourceDefinition} for mdb delivery group.
Expand All @@ -27,9 +27,8 @@
*/
public class MdbDeliveryGroupResourceDefinition extends SimpleResourceDefinition {

public static final String MDB_DELIVERY_GROUP_CAPABILITY_NAME = "org.wildfly.ejb3.mdb-delivery-group";
public static final RuntimeCapability<Void> MDB_DELIVERY_GROUP_CAPABILITY =
RuntimeCapability.Builder.of(MDB_DELIVERY_GROUP_CAPABILITY_NAME, true, Service.NULL.getClass()).build();
public static final UnaryServiceDescriptor<Void> MDB_DELIVERY_GROUP = UnaryServiceDescriptor.of("org.wildfly.ejb3.mdb-delivery-group", Void.class);
static final RuntimeCapability<Void> MDB_DELIVERY_GROUP_CAPABILITY = RuntimeCapability.Builder.of(MDB_DELIVERY_GROUP).build();

public static final SimpleAttributeDefinition ACTIVE = new SimpleAttributeDefinitionBuilder(EJB3SubsystemModel.MDB_DELVIERY_GROUP_ACTIVE, ModelType.BOOLEAN, true)
.setAllowExpression(true)
Expand All @@ -38,15 +37,15 @@ public class MdbDeliveryGroupResourceDefinition extends SimpleResourceDefinition

MdbDeliveryGroupResourceDefinition() {
super(new SimpleResourceDefinition.Parameters(EJB3SubsystemModel.MDB_DELIVERY_GROUP_PATH, EJB3Extension.getResourceDescriptionResolver(EJB3SubsystemModel.MDB_DELIVERY_GROUP))
.setAddHandler(MdbDeliveryGroupAdd.INSTANCE)
.setAddHandler(new MdbDeliveryGroupAdd())
.setRemoveHandler(ReloadRequiredRemoveStepHandler.INSTANCE)
.setCapabilities(MDB_DELIVERY_GROUP_CAPABILITY));
}

@Override
public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
resourceRegistration.registerReadWriteAttribute(ACTIVE, null,
new AbstractWriteAttributeHandler<Void>(ACTIVE) {
new AbstractWriteAttributeHandler<Void>() {
@Override
protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation,
String attributeName, ModelNode resolvedValue, ModelNode currentValue,
Expand All @@ -68,7 +67,7 @@ protected void updateDeliveryGroup(OperationContext context, ModelNode currentVa
}

String groupName = context.getCurrentAddressValue();
ServiceName deliveryGroupServiceName = context.getCapabilityServiceName(MdbDeliveryGroupResourceDefinition.MDB_DELIVERY_GROUP_CAPABILITY_NAME, Service.NULL.getClass(), groupName);
ServiceName deliveryGroupServiceName = context.getCapabilityServiceName(MDB_DELIVERY_GROUP, groupName);

context.getServiceRegistry(true).getRequiredService(deliveryGroupServiceName)
.setMode(resolvedValue.asBoolean() ? ServiceController.Mode.ACTIVE : ServiceController.Mode.NEVER);
Expand Down

0 comments on commit a24b44c

Please sign in to comment.