From 9b1ec6485653ca3d04b0f31301757f63b26c5677 Mon Sep 17 00:00:00 2001 From: Paul Ferraro Date: Thu, 20 Jul 2023 08:55:58 -0400 Subject: [PATCH 1/3] WFCORE-6400 Extract interfaces from CapabilityServiceTarget/CapabilityServiceBuilder for resolving capability dependencies. --- .../controller/CapabilityServiceBuilder.java | 18 +------ .../controller/CapabilityServiceTarget.java | 8 +-- .../as/controller/OperationContextImpl.java | 5 ++ .../controller/RequirementServiceBuilder.java | 51 +++++++++++++++++++ .../controller/RequirementServiceTarget.java | 39 ++++++++++++++ 5 files changed, 102 insertions(+), 19 deletions(-) create mode 100644 controller/src/main/java/org/jboss/as/controller/RequirementServiceBuilder.java create mode 100644 controller/src/main/java/org/jboss/as/controller/RequirementServiceTarget.java diff --git a/controller/src/main/java/org/jboss/as/controller/CapabilityServiceBuilder.java b/controller/src/main/java/org/jboss/as/controller/CapabilityServiceBuilder.java index c645dd03f97..6fbc8d34fee 100644 --- a/controller/src/main/java/org/jboss/as/controller/CapabilityServiceBuilder.java +++ b/controller/src/main/java/org/jboss/as/controller/CapabilityServiceBuilder.java @@ -19,25 +19,22 @@ package org.jboss.as.controller; import java.util.function.Consumer; -import java.util.function.Supplier; import org.jboss.as.controller.capability.RuntimeCapability; import org.jboss.msc.Service; import org.jboss.msc.service.LifecycleListener; -import org.jboss.msc.service.ServiceBuilder; import org.jboss.msc.service.ServiceController; import org.jboss.msc.service.ServiceName; /** * A builder for an individual service in a {@code CapabilityServiceTarget}. - * Create an instance via the {@link CapabilityServiceTarget#addCapability(RuntimeCapability)}. - * Builder also adds support to define capability requirement via {@link #requiresCapability(String, Class, String...)}. + * Create an instance via the {@link CapabilityServiceTarget#addService()} method. * * @param the service type * @author Tomaz Cerar (c) 2017 Red Hat Inc. * @author Richard Opalka */ -public interface CapabilityServiceBuilder extends ServiceBuilder { +public interface CapabilityServiceBuilder extends RequirementServiceBuilder { @Override CapabilityServiceBuilder setInitialMode(ServiceController.Mode mode); @@ -86,15 +83,4 @@ public interface CapabilityServiceBuilder extends ServiceBuilder { * @return consumer providing value */ Consumer provides(final RuntimeCapability[] capabilities, final ServiceName[] aliases); - - /** - * Capability requirement. - * - * @param capabilityName name of capability requirement - * @param dependencyType the class of the value of the dependency - * @param the type of the value of the dependency - * @param referenceNames dynamic part(s) of capability name, only useful when using dynamic named capabilities - * @return readonly dependency reference - */ - Supplier requiresCapability(String capabilityName, Class dependencyType, String... referenceNames); } diff --git a/controller/src/main/java/org/jboss/as/controller/CapabilityServiceTarget.java b/controller/src/main/java/org/jboss/as/controller/CapabilityServiceTarget.java index 7386298f734..287625ff613 100644 --- a/controller/src/main/java/org/jboss/as/controller/CapabilityServiceTarget.java +++ b/controller/src/main/java/org/jboss/as/controller/CapabilityServiceTarget.java @@ -20,7 +20,6 @@ import org.jboss.as.controller.capability.RuntimeCapability; import org.jboss.msc.service.LifecycleListener; -import org.jboss.msc.service.ServiceTarget; /** * The target of ServiceBuilder for capability installations. @@ -32,10 +31,10 @@ * @author Richard Opalka * @author Paul Ferraro */ -public interface CapabilityServiceTarget extends ServiceTarget { +public interface CapabilityServiceTarget extends RequirementServiceTarget { /** - * Gets a builder which can be used to add a capability service into this capability target. + * Returns a builder for installing a service that provides a capability. * * @param capability the capability to be installed * @return new capability builder instance @@ -53,4 +52,7 @@ public interface CapabilityServiceTarget extends ServiceTarget { @Override CapabilityServiceTarget removeListener(LifecycleListener listener); + + @Override + CapabilityServiceTarget subTarget(); } diff --git a/controller/src/main/java/org/jboss/as/controller/OperationContextImpl.java b/controller/src/main/java/org/jboss/as/controller/OperationContextImpl.java index 7451f89896c..85ce649664e 100644 --- a/controller/src/main/java/org/jboss/as/controller/OperationContextImpl.java +++ b/controller/src/main/java/org/jboss/as/controller/OperationContextImpl.java @@ -2194,6 +2194,11 @@ public ContextServiceTarget removeListener(LifecycleListener listener) { return this; } + @Override + public CapabilityServiceTarget subTarget() { + return new ContextServiceTarget(super.subTarget(), this.builderSupplier, this.targetAddress); + } + private static final class ProvidedValuesTrackingServiceBuilder extends DelegatingServiceBuilder { private final Set providedValues = new HashSet<>(); diff --git a/controller/src/main/java/org/jboss/as/controller/RequirementServiceBuilder.java b/controller/src/main/java/org/jboss/as/controller/RequirementServiceBuilder.java new file mode 100644 index 00000000000..156ce5a07d4 --- /dev/null +++ b/controller/src/main/java/org/jboss/as/controller/RequirementServiceBuilder.java @@ -0,0 +1,51 @@ +/* + * Copyright 2023 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jboss.as.controller; + +import java.util.function.Supplier; + +import org.jboss.msc.Service; +import org.jboss.msc.service.LifecycleListener; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceController; + +/** + * A {@link org.jboss.msc.service.ServiceBuilder} that supports capability requirements. + * @param an ignored service value type + * @author Paul Ferraro + */ +public interface RequirementServiceBuilder extends ServiceBuilder { + + @Override + RequirementServiceBuilder setInitialMode(ServiceController.Mode mode); + + @Override + RequirementServiceBuilder setInstance(Service service); + + @Override + RequirementServiceBuilder addListener(LifecycleListener listener); + + /** + * Registers a requirement on the specified capability. + * @param capabilityName name of capability requirement + * @param dependencyType the class of the value of the dependency + * @param referenceNames dynamic part(s) of capability name, only useful when using dynamic named capabilities + * @param the type of the value of the dependency + * @return a reference to the required dependency + */ + Supplier requiresCapability(String capabilityName, Class dependencyType, String... referenceNames); +} diff --git a/controller/src/main/java/org/jboss/as/controller/RequirementServiceTarget.java b/controller/src/main/java/org/jboss/as/controller/RequirementServiceTarget.java new file mode 100644 index 00000000000..7e73976de97 --- /dev/null +++ b/controller/src/main/java/org/jboss/as/controller/RequirementServiceTarget.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jboss.as.controller; + +import org.jboss.msc.service.LifecycleListener; +import org.jboss.msc.service.ServiceTarget; + +/** + * {@link org.jboss.msc.service.ServiceTarget} whose builders support capability requirements. + * @author Paul Ferraro + */ +public interface RequirementServiceTarget extends ServiceTarget { + + @Override + RequirementServiceBuilder addService(); + + @Override + RequirementServiceTarget addListener(LifecycleListener listener); + + @Override + RequirementServiceTarget removeListener(LifecycleListener listener); + + @Override + RequirementServiceTarget subTarget(); +} From 5fe19e071fdf16bf34eefcf94a2734ba4d1e3772 Mon Sep 17 00:00:00 2001 From: Paul Ferraro Date: Thu, 20 Jul 2023 09:04:26 -0400 Subject: [PATCH 2/3] WFCORE-6400 Update DeploymentPhaseContext to return a ServiceTarget capable of resolving capability requirements. --- .../deployment/DeploymentPhaseContext.java | 17 ++++- .../DeploymentPhaseContextImpl.java | 13 ++-- .../DeploymentUnitPhaseService.java | 71 ++++++++++++++++++- 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/server/src/main/java/org/jboss/as/server/deployment/DeploymentPhaseContext.java b/server/src/main/java/org/jboss/as/server/deployment/DeploymentPhaseContext.java index 13ce6e2b6d4..4fcdaa6ac3d 100644 --- a/server/src/main/java/org/jboss/as/server/deployment/DeploymentPhaseContext.java +++ b/server/src/main/java/org/jboss/as/server/deployment/DeploymentPhaseContext.java @@ -22,6 +22,7 @@ package org.jboss.as.server.deployment; +import org.jboss.as.controller.RequirementServiceTarget; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.ServiceRegistry; import org.jboss.msc.service.ServiceTarget; @@ -51,8 +52,22 @@ public interface DeploymentPhaseContext extends Attachable { * the {@link #getPhaseServiceName()} method. * * @return the service target + * @deprecated Use {@link #getRequirementServiceTarget()} instead. */ - ServiceTarget getServiceTarget(); + @Deprecated(forRemoval = true) + default ServiceTarget getServiceTarget() { + return this.getRequirementServiceTarget(); + } + + /** + * Returns the target into which this phase should install services. + * Please note that services added via this context do not have any implicit dependencies by default; + * any root-level deployment services that you add should depend on the service name of the current phase, + * acquired via the {@link #getPhaseServiceName()} method. + * + * @return the service target + */ + RequirementServiceTarget getRequirementServiceTarget(); /** * Get the service registry for the container, which may be used to look up services. diff --git a/server/src/main/java/org/jboss/as/server/deployment/DeploymentPhaseContextImpl.java b/server/src/main/java/org/jboss/as/server/deployment/DeploymentPhaseContextImpl.java index 9e898cf7ce5..b63d9267c07 100644 --- a/server/src/main/java/org/jboss/as/server/deployment/DeploymentPhaseContextImpl.java +++ b/server/src/main/java/org/jboss/as/server/deployment/DeploymentPhaseContextImpl.java @@ -24,23 +24,23 @@ import java.util.List; +import org.jboss.as.controller.RequirementServiceTarget; import org.jboss.msc.service.ServiceBuilder; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.ServiceRegistry; -import org.jboss.msc.service.ServiceTarget; /** * @author David M. Lloyd * @author Richard Opalka */ final class DeploymentPhaseContextImpl extends SimpleAttachable implements DeploymentPhaseContext { - private final ServiceTarget serviceTarget; + private final RequirementServiceTarget serviceTarget; private final ServiceRegistry serviceRegistry; private final List dependencies; private final DeploymentUnit deploymentUnitContext; private final Phase phase; - DeploymentPhaseContextImpl(final ServiceTarget serviceTarget, final ServiceRegistry serviceRegistry, final List dependencies, final DeploymentUnit deploymentUnitContext, final Phase phase) { + DeploymentPhaseContextImpl(final RequirementServiceTarget serviceTarget, final ServiceRegistry serviceRegistry, final List dependencies, final DeploymentUnit deploymentUnitContext, final Phase phase) { this.serviceTarget = serviceTarget; this.serviceRegistry = serviceRegistry; this.dependencies = dependencies; @@ -48,22 +48,27 @@ final class DeploymentPhaseContextImpl extends SimpleAttachable implements Deplo this.phase = phase; } + @Override public ServiceName getPhaseServiceName() { return deploymentUnitContext.getServiceName().append(phase.name()); } - public ServiceTarget getServiceTarget() { + @Override + public RequirementServiceTarget getRequirementServiceTarget() { return serviceTarget; } + @Override public ServiceRegistry getServiceRegistry() { return serviceRegistry; } + @Override public DeploymentUnit getDeploymentUnit() { return deploymentUnitContext; } + @Override public Phase getPhase() { return phase; } diff --git a/server/src/main/java/org/jboss/as/server/deployment/DeploymentUnitPhaseService.java b/server/src/main/java/org/jboss/as/server/deployment/DeploymentUnitPhaseService.java index 56d0d231050..4cf68a4685e 100644 --- a/server/src/main/java/org/jboss/as/server/deployment/DeploymentUnitPhaseService.java +++ b/server/src/main/java/org/jboss/as/server/deployment/DeploymentUnitPhaseService.java @@ -29,13 +29,19 @@ import java.util.ListIterator; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; +import org.jboss.as.controller.RequirementServiceBuilder; +import org.jboss.as.controller.RequirementServiceTarget; +import org.jboss.as.controller.capability.CapabilityServiceSupport; import org.jboss.as.server.deployment.module.ModuleSpecification; import org.jboss.as.server.logging.ServerLogger; import org.jboss.modules.ModuleIdentifier; import org.jboss.msc.service.LifecycleEvent; import org.jboss.msc.service.LifecycleListener; +import org.jboss.msc.service.DelegatingServiceBuilder; import org.jboss.msc.service.DelegatingServiceRegistry; +import org.jboss.msc.service.DelegatingServiceTarget; import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceBuilder; import org.jboss.msc.service.ServiceContainer; @@ -119,7 +125,7 @@ public void handleEvent(final ServiceController controller, final LifecycleEv final List list = chains.getChain(phase); final ListIterator iterator = list.listIterator(); final ServiceContainer container = context.getController().getServiceContainer(); - final ServiceTarget serviceTarget = context.getChildTarget().subTarget(); + final RequirementServiceTarget serviceTarget = new DeploymentUnitServiceTarget(context.getChildTarget().subTarget(), deploymentUnit.getAttachment(Attachments.CAPABILITY_SERVICE_SUPPORT)); final DeploymentUnit parent = deploymentUnit.getParent(); final List dependencies = new LinkedList<>(); @@ -277,4 +283,67 @@ private static boolean shouldRun(final DeploymentUnit unit, final RegisteredDepl } return !shouldNotRun.contains(deployer.getSubsystemName()); } + + static class DeploymentUnitServiceTarget extends DelegatingServiceTarget implements RequirementServiceTarget { + private final CapabilityServiceSupport support; + + DeploymentUnitServiceTarget(ServiceTarget target, CapabilityServiceSupport support) { + super(target); + this.support = support; + } + + @Override + public RequirementServiceTarget addListener(LifecycleListener listener) { + super.addListener(listener); + return this; + } + + @Override + public RequirementServiceTarget removeListener(LifecycleListener listener) { + super.removeListener(listener); + return this; + } + + @Override + public RequirementServiceTarget subTarget() { + return new DeploymentUnitServiceTarget(super.subTarget(), this.support); + } + + @Override + public RequirementServiceBuilder addService() { + return new DeploymentUnitServiceBuilder<>(super.addService(), this.support); + } + } + + static class DeploymentUnitServiceBuilder extends DelegatingServiceBuilder implements RequirementServiceBuilder { + private final CapabilityServiceSupport support; + + DeploymentUnitServiceBuilder(ServiceBuilder builder, CapabilityServiceSupport support) { + super(builder); + this.support = support; + } + + @Override + public RequirementServiceBuilder setInitialMode(Mode mode) { + super.setInitialMode(mode); + return this; + } + + @Override + public RequirementServiceBuilder setInstance(org.jboss.msc.Service service) { + super.setInstance(service); + return this; + } + + @Override + public RequirementServiceBuilder addListener(LifecycleListener listener) { + super.addListener(listener); + return this; + } + + @Override + public Supplier requiresCapability(String capabilityName, Class dependencyType, String... referenceNames) { + return super.requires(this.support.getCapabilityServiceName(capabilityName, referenceNames)); + } + } } From 73e7c8c555e40f3c03acdc789703480b6078d713 Mon Sep 17 00:00:00 2001 From: Paul Ferraro Date: Tue, 1 Aug 2023 09:06:49 -0400 Subject: [PATCH 3/3] Deprecated CapabilityServiceTarget.addService(ServiceName) should also support capability dependency resolution. --- .../controller/CapabilityServiceTarget.java | 5 +++ .../as/controller/OperationContextImpl.java | 39 ++++++------------- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/controller/src/main/java/org/jboss/as/controller/CapabilityServiceTarget.java b/controller/src/main/java/org/jboss/as/controller/CapabilityServiceTarget.java index 287625ff613..cd3f61a38aa 100644 --- a/controller/src/main/java/org/jboss/as/controller/CapabilityServiceTarget.java +++ b/controller/src/main/java/org/jboss/as/controller/CapabilityServiceTarget.java @@ -20,6 +20,7 @@ import org.jboss.as.controller.capability.RuntimeCapability; import org.jboss.msc.service.LifecycleListener; +import org.jboss.msc.service.ServiceName; /** * The target of ServiceBuilder for capability installations. @@ -47,6 +48,10 @@ public interface CapabilityServiceTarget extends RequirementServiceTarget { @Override CapabilityServiceBuilder addService(); + @Deprecated + @Override + CapabilityServiceBuilder addService(ServiceName name); + @Override CapabilityServiceTarget addListener(LifecycleListener listener); diff --git a/controller/src/main/java/org/jboss/as/controller/OperationContextImpl.java b/controller/src/main/java/org/jboss/as/controller/OperationContextImpl.java index 85ce649664e..b0fd9c71eac 100644 --- a/controller/src/main/java/org/jboss/as/controller/OperationContextImpl.java +++ b/controller/src/main/java/org/jboss/as/controller/OperationContextImpl.java @@ -2139,44 +2139,27 @@ synchronized void done() { @Override public CapabilityServiceBuilder addService() { - final ServiceBuilder realBuilder = new ProvidedValuesTrackingServiceBuilder(super.getDelegate().addService()); - // If done() has been called we are no longer associated with a management op and should just - // return the builder from delegate - synchronized (this) { - if (builderSupplier == null) { - return new CapabilityServiceBuilderImpl<>(realBuilder, targetAddress); - } - ContextServiceBuilder csb = builderSupplier.getContextServiceBuilder(realBuilder); - builders.add(csb); - return new CapabilityServiceBuilderImpl<>(csb, targetAddress); - } + return this.wrap(new ProvidedValuesTrackingServiceBuilder(super.getDelegate().addService())); } @Override - public ServiceBuilder addService(final ServiceName name) { - final ServiceBuilder realBuilder = new ProvidedValuesTrackingServiceBuilder(super.getDelegate().addService(name), name); - // If done() has been called we are no longer associated with a management op and should just - // return the builder from delegate - synchronized (this) { - if (builderSupplier == null) { - return realBuilder; - } - ContextServiceBuilder csb = builderSupplier.getContextServiceBuilder(realBuilder); - builders.add(csb); - return csb; - } + public CapabilityServiceBuilder addService(final ServiceName name) { + return this.wrap(new ProvidedValuesTrackingServiceBuilder(super.getDelegate().addService(name), name)); } @Override public CapabilityServiceBuilder addService(final ServiceName name, final org.jboss.msc.service.Service service) throws IllegalArgumentException { - final ServiceBuilder realBuilder = new ProvidedValuesTrackingServiceBuilder(super.getDelegate().addService(name, service), name); + return this.wrap(new ProvidedValuesTrackingServiceBuilder(super.getDelegate().addService(name, service), name)); + } + + private CapabilityServiceBuilder wrap(ServiceBuilder builder) { // If done() has been called we are no longer associated with a management op and should just // return the builder from delegate synchronized (this) { if (builderSupplier == null) { - return new CapabilityServiceBuilderImpl<>(realBuilder, targetAddress); + return new CapabilityServiceBuilderImpl<>(builder, targetAddress); } - ContextServiceBuilder csb = builderSupplier.getContextServiceBuilder(realBuilder); + ContextServiceBuilder csb = builderSupplier.getContextServiceBuilder(builder); builders.add(csb); return new CapabilityServiceBuilderImpl<>(csb, targetAddress); } @@ -2228,9 +2211,9 @@ private Set getProvidedValues() { @SuppressWarnings("unchecked") public CapabilityServiceBuilder addCapability(final RuntimeCapability capability) throws IllegalArgumentException { if (capability.isDynamicallyNamed()) { - return new CapabilityServiceBuilderImpl(addService(capability.getCapabilityServiceName(targetAddress)), targetAddress); + return this.addService(capability.getCapabilityServiceName(targetAddress)); } else { - return new CapabilityServiceBuilderImpl(addService(capability.getCapabilityServiceName()), targetAddress); + return this.addService(capability.getCapabilityServiceName()); } }