diff --git a/controller/src/main/java/org/jboss/as/controller/OperationContext.java b/controller/src/main/java/org/jboss/as/controller/OperationContext.java index ce52a017408..6f867f083bb 100644 --- a/controller/src/main/java/org/jboss/as/controller/OperationContext.java +++ b/controller/src/main/java/org/jboss/as/controller/OperationContext.java @@ -712,6 +712,7 @@ default ServiceTarget getServiceTarget() throws UnsupportedOperationException { * manager exists and its {@link SecurityManager#checkPermission checkPermission} method doesn't allow * access to the relevant system property or environment variable */ + @Override ModelNode resolveExpressions(ModelNode node) throws OperationFailedException; /** @@ -837,7 +838,7 @@ default ServiceTarget getServiceTarget() throws UnsupportedOperationException { * * @throws java.lang.IllegalStateException if {@link #getCurrentStage() the current stage} is not {@link Stage#MODEL} */ - void registerCapability(RuntimeCapability capability); + void registerCapability(RuntimeCapability capability); /** * Registers an additional hard requirement a capability has beyond what it was aware of when {@code capability} @@ -885,6 +886,197 @@ default ServiceTarget getServiceTarget() throws UnsupportedOperationException { */ boolean hasOptionalCapability(String requested, String dependent, String attribute); + /** + * Checks whether one of a capability's optional and runtime-only requirements is present. Only for use in cases + * where the {@code dependent} capability's persistent configuration does not mandate the presence + * of the {@code requested} capability, but the capability will use it at runtime if it is present. + *

+ * This method should be used in preference to {@link #registerAdditionalCapabilityRequirement(String, String, String)} + * when the caller's own configuration doesn't impose a hard requirement for the {@code requested} capability, but, + * if it is present it will be used. Once the caller declares an intent to use the capability by invoking this + * method and getting a {@code true} response, thereafter the system is aware that {@code dependent} is actually + * using {@code requested}, but will not prevent configuration changes that make {@code requested} + * unavailable. + *

+ * + * @param requested the base name of the requested capability. Cannot be {@code null} + * @param dependent the runtime capability that requires the other capability. Cannot be {@code null} + * @param attribute the attribute that triggered this requirement, or {@code null} if no single attribute was responsible + * @return {@code true} if the requested capability is present; {@code false} if not. If {@code true}, hereafter + * {@code dependent}'s requirement for {@code requested} will not be treated as optional. + * @throws IllegalStateException if {@link #getCurrentStage() the current stage} is {@link Stage#MODEL}. + * The complete set of capabilities is not known until the end of the model stage. + */ + default boolean hasOptionalCapability(String requested, RuntimeCapability dependent, AttributeDefinition attribute) { + return this.hasOptionalCapability(requested, dependent.isDynamicallyNamed() ? dependent.getDynamicName(this.getCurrentAddress()) : dependent.getName(), (attribute != null) ? attribute.getName() : null); + } + + /** + * Checks whether one of a capability's optional and runtime-only requirements is present. Only for use in cases + * where the {@code dependent} capability's persistent configuration does not mandate the presence + * of the {@code requested} capability, but the capability will use it at runtime if it is present. + *

+ * This method should be used in preference to {@link #registerAdditionalCapabilityRequirement(String, String, String)} + * when the caller's own configuration doesn't impose a hard requirement for the {@code requested} capability, but, + * if it is present it will be used. Once the caller declares an intent to use the capability by invoking this + * method and getting a {@code true} response, thereafter the system is aware that {@code dependent} is actually + * using {@code requested}, but will not prevent configuration changes that make {@code requested} + * unavailable. + *

+ * + * @param requested the base name of the requested capability. Cannot be {@code null} + * @param requestedSegments the dynamic segments of the requested capability. Cannot be {@code null} + * @param dependent the runtime capability that requires the other capability. Cannot be {@code null} + * @param attribute the attribute that triggered this requirement, or {@code null} if no single attribute was responsible + * @return {@code true} if the requested capability is present; {@code false} if not. If {@code true}, hereafter + * {@code dependent}'s requirement for {@code requested} will not be treated as optional. + * @throws IllegalStateException if {@link #getCurrentStage() the current stage} is {@link Stage#MODEL}. + * The complete set of capabilities is not known until the end of the model stage. + */ + default boolean hasOptionalCapability(String requested, String[] requestedSegments, RuntimeCapability dependent, AttributeDefinition attribute) { + return this.hasOptionalCapability(RuntimeCapability.buildDynamicCapabilityName(requested, requestedSegments), dependent, attribute); + } + + /** + * Checks whether one of a capability's optional and runtime-only requirements is present. Only for use in cases + * where the {@code dependent} capability's persistent configuration does not mandate the presence + * of the {@code requested} capability, but the capability will use it at runtime if it is present. + *

+ * This method should be used in preference to {@link #registerAdditionalCapabilityRequirement(String, String, String)} + * when the caller's own configuration doesn't impose a hard requirement for the {@code requested} capability, but, + * if it is present it will be used. Once the caller declares an intent to use the capability by invoking this + * method and getting a {@code true} response, thereafter the system is aware that {@code dependent} is actually + * using {@code requested}, but will not prevent configuration changes that make {@code requested} + * unavailable. + *

+ * + * @param requested the base name of the requested capability. Cannot be {@code null} + * @param requestedSegments the dynamic segments of the requested capability. Cannot be {@code null} + * @param dependent the runtime capability that requires the other capability. Cannot be {@code null} + * @param attribute the attribute that triggered this requirement, or {@code null} if no single attribute was responsible + * @return {@code true} if the requested capability is present; {@code false} if not. If {@code true}, hereafter + * {@code dependent}'s requirement for {@code requested} will not be treated as optional. + * @throws IllegalStateException if {@link #getCurrentStage() the current stage} is {@link Stage#MODEL}. + * The complete set of capabilities is not known until the end of the model stage. + */ + default boolean hasOptionalCapability(NullaryServiceDescriptor requested, RuntimeCapability dependent, AttributeDefinition attribute) { + return this.hasOptionalCapability(requested.getName(), dependent, attribute); + } + + /** + * Checks whether one of a capability's optional and runtime-only requirements is present. Only for use in cases + * where the {@code dependent} capability's persistent configuration does not mandate the presence + * of the {@code requested} capability, but the capability will use it at runtime if it is present. + *

+ * This method should be used in preference to {@link #registerAdditionalCapabilityRequirement(String, String, String)} + * when the caller's own configuration doesn't impose a hard requirement for the {@code requested} capability, but, + * if it is present it will be used. Once the caller declares an intent to use the capability by invoking this + * method and getting a {@code true} response, thereafter the system is aware that {@code dependent} is actually + * using {@code requested}, but will not prevent configuration changes that make {@code requested} + * unavailable. + *

+ * + * @param requested the service descriptor of the requested capability. Cannot be {@code null} + * @param name the dynamic name segment of the requested capability. + * @param dependent the runtime capability that requires the other capability. Cannot be {@code null} + * @param attribute the attribute that triggered this requirement, or {@code null} if no single attribute was responsible + * @return {@code true} if the requested capability is present; {@code false} if not. If {@code true}, hereafter + * {@code dependent}'s requirement for {@code requested} will not be treated as optional. + * @throws IllegalStateException if {@link #getCurrentStage() the current stage} is {@link Stage#MODEL}. + * The complete set of capabilities is not known until the end of the model stage. + */ + default boolean hasOptionalCapability(UnaryServiceDescriptor requested, String name, RuntimeCapability dependent, AttributeDefinition attribute) { + Map.Entry segments = requested.resolve(name); + return this.hasOptionalCapability(segments.getKey(), segments.getValue(), dependent, attribute); + } + + /** + * Checks whether one of a capability's optional and runtime-only requirements is present. Only for use in cases + * where the {@code dependent} capability's persistent configuration does not mandate the presence + * of the {@code requested} capability, but the capability will use it at runtime if it is present. + *

+ * This method should be used in preference to {@link #registerAdditionalCapabilityRequirement(String, String, String)} + * when the caller's own configuration doesn't impose a hard requirement for the {@code requested} capability, but, + * if it is present it will be used. Once the caller declares an intent to use the capability by invoking this + * method and getting a {@code true} response, thereafter the system is aware that {@code dependent} is actually + * using {@code requested}, but will not prevent configuration changes that make {@code requested} + * unavailable. + *

+ * + * @param requested the service descriptor of the requested capability. Cannot be {@code null} + * @param parent the first dynamic name segment of the requested capability. + * @param child the second dynamic name segment of the requested capability. + * @param dependent the runtime capability that requires the other capability. Cannot be {@code null} + * @param attribute the attribute that triggered this requirement, or {@code null} if no single attribute was responsible + * @return {@code true} if the requested capability is present; {@code false} if not. If {@code true}, hereafter + * {@code dependent}'s requirement for {@code requested} will not be treated as optional. + * @throws IllegalStateException if {@link #getCurrentStage() the current stage} is {@link Stage#MODEL}. + * The complete set of capabilities is not known until the end of the model stage. + */ + default boolean hasOptionalCapability(BinaryServiceDescriptor requested, String parent, String child, RuntimeCapability dependent, AttributeDefinition attribute) { + Map.Entry segments = requested.resolve(parent, child); + return this.hasOptionalCapability(segments.getKey(), segments.getValue(), dependent, attribute); + } + + /** + * Checks whether one of a capability's optional and runtime-only requirements is present. Only for use in cases + * where the {@code dependent} capability's persistent configuration does not mandate the presence + * of the {@code requested} capability, but the capability will use it at runtime if it is present. + *

+ * This method should be used in preference to {@link #registerAdditionalCapabilityRequirement(String, String, String)} + * when the caller's own configuration doesn't impose a hard requirement for the {@code requested} capability, but, + * if it is present it will be used. Once the caller declares an intent to use the capability by invoking this + * method and getting a {@code true} response, thereafter the system is aware that {@code dependent} is actually + * using {@code requested}, but will not prevent configuration changes that make {@code requested} + * unavailable. + *

+ * + * @param requested the service descriptor of the requested capability. Cannot be {@code null} + * @param grandparent the first dynamic name segment of the requested capability. + * @param parent the second dynamic name segment of the requested capability. + * @param child the third dynamic name segment of the requested capability. + * @param dependent the runtime capability that requires the other capability. Cannot be {@code null} + * @param attribute the attribute that triggered this requirement, or {@code null} if no single attribute was responsible + * @return {@code true} if the requested capability is present; {@code false} if not. If {@code true}, hereafter + * {@code dependent}'s requirement for {@code requested} will not be treated as optional. + * @throws IllegalStateException if {@link #getCurrentStage() the current stage} is {@link Stage#MODEL}. + * The complete set of capabilities is not known until the end of the model stage. + */ + default boolean hasOptionalCapability(TernaryServiceDescriptor requested, String grandparent, String parent, String child, RuntimeCapability dependent, AttributeDefinition attribute) { + Map.Entry segments = requested.resolve(grandparent, parent, child); + return this.hasOptionalCapability(segments.getKey(), segments.getValue(), dependent, attribute); + } + + /** + * Checks whether one of a capability's optional and runtime-only requirements is present. Only for use in cases + * where the {@code dependent} capability's persistent configuration does not mandate the presence + * of the {@code requested} capability, but the capability will use it at runtime if it is present. + *

+ * This method should be used in preference to {@link #registerAdditionalCapabilityRequirement(String, String, String)} + * when the caller's own configuration doesn't impose a hard requirement for the {@code requested} capability, but, + * if it is present it will be used. Once the caller declares an intent to use the capability by invoking this + * method and getting a {@code true} response, thereafter the system is aware that {@code dependent} is actually + * using {@code requested}, but will not prevent configuration changes that make {@code requested} + * unavailable. + *

+ * + * @param requested the service descriptor of the requested capability. Cannot be {@code null} + * @param greatGrandparent the first dynamic name segment of the requested capability. + * @param grandparent the second dynamic name segment of the requested capability. + * @param parent the third dynamic name segment of the requested capability. + * @param child the fourth dynamic name segment of the requested capability. + * @param dependent the runtime capability that requires the other capability. Cannot be {@code null} + * @param attribute the attribute that triggered this requirement, or {@code null} if no single attribute was responsible + * @return {@code true} if the requested capability is present; {@code false} if not. If {@code true}, hereafter + * {@code dependent}'s requirement for {@code requested} will not be treated as optional. + * @throws IllegalStateException if {@link #getCurrentStage() the current stage} is {@link Stage#MODEL}. + * The complete set of capabilities is not known until the end of the model stage. + */ + default boolean hasOptionalCapability(QuaternaryServiceDescriptor requested, String greatGrandparent, String grandparent, String parent, String child, RuntimeCapability dependent, AttributeDefinition attribute) { + Map.Entry segments = requested.resolve(greatGrandparent, grandparent, parent, child); + return this.hasOptionalCapability(segments.getKey(), segments.getValue(), dependent, attribute); + } + /** * Requests that one of a capability's optional requirements hereafter be treated as required, until the process is * stopped or reloaded. This request will only be granted if the required capability is already present; otherwise 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 b76f313af84..06ce4f6ebc3 100644 --- a/controller/src/main/java/org/jboss/as/controller/OperationContextImpl.java +++ b/controller/src/main/java/org/jboss/as/controller/OperationContextImpl.java @@ -107,6 +107,7 @@ import org.jboss.msc.service.ServiceRegistry; import org.jboss.msc.service.ServiceRegistryException; import org.jboss.msc.service.ServiceTarget; +import org.wildfly.common.Assert; import org.wildfly.security.auth.server.SecurityIdentity; /** @@ -1564,6 +1565,8 @@ private void recordRequirement(RuntimeRequirementRegistration reg, Step step) { @Override public boolean hasOptionalCapability(String required, String dependent, String attribute) { + Assert.checkNotNullParam("required", required); + Assert.checkNotNullParam("dependent", dependent); return requestOptionalCapability(required, dependent, true, activeStep, attribute); } @@ -1572,12 +1575,6 @@ boolean requestOptionalCapability(String required, String dependent, boolean run assertCapabilitiesAvailable(currentStage); ensureLocalCapabilityRegistry(); RuntimeCapabilityRegistry registry = managementModel.getCapabilityRegistry(); - if (dependent == null) { - // WFCORE-900 we're currently forgiving of this, but only for runtime-only requirements - assert runtimeOnly; - CapabilityScope context = createCapabilityContext(step.address); - return registry.hasCapability(required, context); - } RuntimeRequirementRegistration registration = createRequirementRegistration(required, dependent, runtimeOnly, step, attribute); CapabilityScope context = registration.getDependentContext(); if (registry.hasCapability(required, context)) { @@ -1590,6 +1587,8 @@ boolean requestOptionalCapability(String required, String dependent, boolean run @Override public void requireOptionalCapability(String required, String dependent, String attribute) throws OperationFailedException { + Assert.checkNotNullParam("required", required); + Assert.checkNotNullParam("dependent", dependent); requireOptionalCapability(required, dependent, activeStep, attribute); } diff --git a/controller/src/main/java/org/jboss/as/controller/capability/CapabilityServiceSupport.java b/controller/src/main/java/org/jboss/as/controller/capability/CapabilityServiceSupport.java index 926b0f0a044..22186fea5e3 100644 --- a/controller/src/main/java/org/jboss/as/controller/capability/CapabilityServiceSupport.java +++ b/controller/src/main/java/org/jboss/as/controller/capability/CapabilityServiceSupport.java @@ -40,6 +40,7 @@ public NoSuchCapabilityException(String message) { super(message); } } + /** * Gets whether a runtime capability with the given name is registered. * @@ -48,6 +49,81 @@ public NoSuchCapabilityException(String message) { */ boolean hasCapability(String capabilityName); + /** + * Indicates whether a runtime capability with the given name and segments is registered. + * + * @param capabilityName the name of the capability. Cannot be {@code null} + * @parem segments the dynamic name segments of the capability. Cannot be {@code null} + * @return {@code true} if there is a capability with the given name registered + */ + default boolean hasCapability(String capabilityName, String... segments) { + return this.hasCapability(RuntimeCapability.buildDynamicCapabilityName(capabilityName, segments)); + } + + /** + * Indicates whether or not a runtime capability with the given descriptor is registered. + * + * @param descriptor the service descriptor of the requested capability + * @return {@code true} if there is a capability with the resolved name registered + */ + default boolean hasCapability(NullaryServiceDescriptor descriptor) { + return this.hasCapability(descriptor.getName()); + } + + /** + * Indicates whether or not a runtime capability with the given descriptor and segment is registered. + * + * @param descriptor the service descriptor of the requested capability + * @param name the dynamic name segment of the requested capability. + * @return {@code true} if there is a capability with the resolved name registered + */ + default boolean hasCapability(UnaryServiceDescriptor descriptor, String name) { + Map.Entry segments = descriptor.resolve(name); + return this.hasCapability(segments.getKey(), segments.getValue()); + } + + /** + * Indicates whether or not a runtime capability with the given descriptor and segments is registered. + * + * @param descriptor the service descriptor of the requested capability + * @param parent the first dynamic name segment of the requested capability. + * @param child the second dynamic name segment of the requested capability. + * @return {@code true} if there is a capability with the resolved name registered + */ + default boolean hasCapability(BinaryServiceDescriptor descriptor, String parent, String child) { + Map.Entry segments = descriptor.resolve(parent, child); + return this.hasCapability(segments.getKey(), segments.getValue()); + } + + /** + * Indicates whether or not a runtime capability with the given descriptor and segments is registered. + * + * @param descriptor the service descriptor of the requested capability + * @param grandparent the first dynamic name segment of the requested capability. + * @param parent the second dynamic name segment of the requested capability. + * @param child the third dynamic name segment of the requested capability. + * @return {@code true} if there is a capability with the resolved name registered + */ + default boolean hasCapability(TernaryServiceDescriptor descriptor, String grandparent, String parent, String child) { + Map.Entry segments = descriptor.resolve(grandparent, parent, child); + return this.hasCapability(segments.getKey(), segments.getValue()); + } + + /** + * Indicates whether or not a runtime capability with the given descriptor and segments is registered. + * + * @param descriptor the service descriptor of the requested capability + * @param greatGrandparent the first dynamic name segment of the requested capability. + * @param grandparent the second dynamic name segment of the requested capability. + * @param parent the third dynamic name segment of the requested capability. + * @param child the fourth dynamic name segment of the requested capability. + * @return {@code true} if there is a capability with the resolved name registered + */ + default boolean hasCapability(QuaternaryServiceDescriptor descriptor, String greatGrandparent, String grandparent, String parent, String child) { + Map.Entry segments = descriptor.resolve(greatGrandparent, grandparent, parent, child); + return this.hasCapability(segments.getKey(), segments.getValue()); + } + /** * Gets the runtime API associated with a given capability, if there is one. * @param capabilityName the name of the capability. Cannot be {@code null} diff --git a/controller/src/test/java/org/jboss/as/controller/SocketCapabilityResolutionUnitTestCase.java b/controller/src/test/java/org/jboss/as/controller/SocketCapabilityResolutionUnitTestCase.java index 1f5de665a0f..25266a41962 100644 --- a/controller/src/test/java/org/jboss/as/controller/SocketCapabilityResolutionUnitTestCase.java +++ b/controller/src/test/java/org/jboss/as/controller/SocketCapabilityResolutionUnitTestCase.java @@ -245,12 +245,10 @@ public void testInconsistentParentChildProfile() { } @Test - public void testWFCORE900() { + public void testRevertedWFCORE900() { ModelNode op = getCompositeOperation(getCapabilityOperation(SOCKET_A_1, "cap_a"), getCapabilityOperation(GLOBAL_A, null, "cap_a")); ModelNode response = controller.execute(op, null, null, null); - // NOTE: IT IS FINE TO CHANGE THESE ASSERTIONS IF WFCORE-900 SUPPORT IS RESCINDED! - assertEquals(response.toString(), SUCCESS, response.get(OUTCOME).asString()); - assertTrue(response.toString(), response.get(RESULT, "step-2", RESULT).asBoolean()); + assertEquals(response.toString(), FAILED, response.get(OUTCOME).asString()); } @Test diff --git a/remoting/subsystem/src/main/java/org/jboss/as/remoting/management/ManagementRemotingServices.java b/remoting/subsystem/src/main/java/org/jboss/as/remoting/management/ManagementRemotingServices.java index 5d0b3556432..2d3c50261c6 100644 --- a/remoting/subsystem/src/main/java/org/jboss/as/remoting/management/ManagementRemotingServices.java +++ b/remoting/subsystem/src/main/java/org/jboss/as/remoting/management/ManagementRemotingServices.java @@ -81,7 +81,7 @@ public static void installDomainConnectorServices(final OperationContext context final OptionMap options, final ServiceName saslAuthenticationFactory, final ServiceName sslContext) { - ServiceName sbmName = context.hasOptionalCapability(SocketBindingManager.SERVICE_DESCRIPTOR.getName(), NATIVE_MANAGEMENT_RUNTIME_CAPABILITY.getName(), null) + ServiceName sbmName = context.hasOptionalCapability(SocketBindingManager.SERVICE_DESCRIPTOR, NATIVE_MANAGEMENT_RUNTIME_CAPABILITY, null) ? context.getCapabilityServiceName(SocketBindingManager.SERVICE_DESCRIPTOR) : null; installConnectorServicesForNetworkInterfaceBinding(serviceTarget, endpointName, MANAGEMENT_CONNECTOR, networkInterfaceBinding, port, options, saslAuthenticationFactory, sslContext, sbmName);