diff --git a/controller/src/main/java/org/jboss/as/controller/DefaultCapabilityServiceSupport.java b/controller/src/main/java/org/jboss/as/controller/DefaultCapabilityServiceSupport.java new file mode 100644 index 00000000000..69705e28aa8 --- /dev/null +++ b/controller/src/main/java/org/jboss/as/controller/DefaultCapabilityServiceSupport.java @@ -0,0 +1,88 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.jboss.as.controller; + +import static org.wildfly.common.Assert.checkNotNullParam; + +import java.util.Optional; + +import org.jboss.as.controller.capability.CapabilityServiceSupport; +import org.jboss.as.controller.capability.RuntimeCapability; +import org.jboss.as.controller.capability.registry.CapabilityScope; +import org.jboss.as.controller.capability.registry.ImmutableCapabilityRegistry; +import org.jboss.as.controller.logging.ControllerLogger; +import org.jboss.msc.service.ServiceName; + +/** + * Default implementation of {@link CapabilityServiceSupport}. + */ +public final class DefaultCapabilityServiceSupport implements CapabilityServiceSupport { + private final ImmutableCapabilityRegistry registry; + + /** + * Creates a new DefaultCapabilityServiceSupport. + * @param registry a capability registry. Cannot be {@code null}. + */ + public DefaultCapabilityServiceSupport(ImmutableCapabilityRegistry registry) { + checkNotNullParam("registry", registry); + this.registry = registry; + } + + @Override + public boolean hasCapability(String capabilityName) { + return registry.hasCapability(capabilityName, CapabilityScope.GLOBAL); + } + + @Override + public T getCapabilityRuntimeAPI(String capabilityName, Class apiType) throws NoSuchCapabilityException { + try { + return registry.getCapabilityRuntimeAPI(capabilityName, CapabilityScope.GLOBAL, apiType); + } catch (IllegalStateException e) { + throw new NoSuchCapabilityException(capabilityName); + } + } + + @Override + public T getCapabilityRuntimeAPI(String capabilityBaseName, String dynamicPart, Class apiType) throws NoSuchCapabilityException { + String fullName = RuntimeCapability.buildDynamicCapabilityName(capabilityBaseName, dynamicPart); + return getCapabilityRuntimeAPI(fullName, apiType); + } + + @Override + public Optional getOptionalCapabilityRuntimeAPI(String capabilityName, Class apiType) { + try { + return Optional.of(getCapabilityRuntimeAPI(capabilityName, apiType)); + } catch (NoSuchCapabilityException e) { + return Optional.empty(); + } + } + + @Override + public Optional getOptionalCapabilityRuntimeAPI(String capabilityBaseName, String dynamicPart, Class apiType) { + try { + return Optional.of(getCapabilityRuntimeAPI(capabilityBaseName, dynamicPart, apiType)); + } catch (NoSuchCapabilityException e) { + return Optional.empty(); + } + } + + @Override + public ServiceName getCapabilityServiceName(String capabilityName) { + try { + return registry.getCapabilityServiceName(capabilityName, CapabilityScope.GLOBAL, null); + } catch (IllegalStateException | IllegalArgumentException ignore) { + // ignore + } + ControllerLogger.ROOT_LOGGER.debugf("CapabilityServiceSupport: Parsing ServiceName for %s", capabilityName); + return ServiceNameFactory.parseServiceName(capabilityName); + } + + @Override + public ServiceName getCapabilityServiceName(String capabilityBaseName, String... dynamicPart) { + ServiceName name = getCapabilityServiceName(capabilityBaseName); + return (dynamicPart.length > 0) ? name.append(dynamicPart) : name; + } +} diff --git a/controller/src/main/java/org/jboss/as/controller/ExpressionResolver.java b/controller/src/main/java/org/jboss/as/controller/ExpressionResolver.java index 8b526f097db..479626c0887 100644 --- a/controller/src/main/java/org/jboss/as/controller/ExpressionResolver.java +++ b/controller/src/main/java/org/jboss/as/controller/ExpressionResolver.java @@ -6,6 +6,7 @@ import java.util.regex.Pattern; +import org.jboss.as.controller.capability.CapabilityServiceSupport; import org.jboss.as.controller.extension.ExpressionResolverExtension; import org.jboss.as.controller.extension.ResolverExtensionRegistry; import org.jboss.as.controller.logging.ControllerLogger; @@ -23,9 +24,9 @@ public interface ExpressionResolver { Pattern EXPRESSION_PATTERN = Pattern.compile(".*\\$\\{.*}.*"); /** - * Resolves any expressions in the passed in ModelNode. - * - * Expressions may represent system properties, vaulted date, or a custom format to be handled by an + * Resolves any expressions in the passed-in ModelNode. + *

+ * Expressions may represent system properties, environment variables or a custom format to be handled by an * {@link ExpressionResolverExtension} registered using the {@link ResolverExtensionRegistry}. * * @param node the ModelNode containing expressions. @@ -47,13 +48,11 @@ public interface ExpressionResolver { ModelNode resolveExpressions(ModelNode node) throws OperationFailedException; /** - * Resolves any expressions in the passed in ModelNode. - * - * Expressions may represent system properties, vaulted date, or a custom format to be handled by an + * Resolves any expressions in the passed-in ModelNode. + *

+ * Expressions may represent system properties, environment variables or a custom format to be handled by an * {@link ExpressionResolverExtension} registered using the {@link ResolverExtensionRegistry}. * - * For vaulted data the format is ${VAULT::vault_block::attribute_name::sharedKey} - * * @param node the ModelNode containing expressions. * @param context the current {@code OperationContext} to provide additional contextual information. * @return a copy of the node with expressions resolved @@ -75,6 +74,33 @@ default ModelNode resolveExpressions(ModelNode node, OperationContext context) t return resolveExpressions(node); } + /** + * Resolves any expressions in the passed-in ModelNode. + *

+ * Expressions may represent system properties, environment variables or a custom format to be handled by an + * {@link ExpressionResolverExtension} registered using the {@link ResolverExtensionRegistry}. + * + * @param node the ModelNode containing expressions. + * @param capabilitySupport support object for accessing capability-backed APIs. + * @return a copy of the node with expressions resolved + * + * @throws ExpressionResolutionUserException if {@code expression} is a form understood by the resolver but in some + * way is unacceptable. This should only be thrown due to flaws in the + * provided {@code expression} or the configuration of resources used by + * the resolver extension, which are 'user' problems>. It should not + * be used for internal problems in the resolver extension. If a + * if a security manager exists and its + * {@link SecurityManager#checkPermission checkPermission} method doesn't + * allow access to a relevant system property or environment variable, + * an {@code ExpressionResolutionUserException} should be thrown + * @throws OperationFailedException if an {@link ExpressionResolverExtension} throws one from its + * {@link ExpressionResolverExtension#initialize(OperationContext)} method. + * @throws ExpressionResolver.ExpressionResolutionServerException if some other internal expression resolution failure occurs. + */ + default ModelNode resolveExpressions(ModelNode node, CapabilityServiceSupport capabilitySupport) throws OperationFailedException { + return resolveExpressions(node); + } + /** * An {@code ExpressionResolver} that can only resolve from system properties * and environment variables. Should not be used for most product resolution use cases as it does diff --git a/controller/src/main/java/org/jboss/as/controller/ExpressionResolverImpl.java b/controller/src/main/java/org/jboss/as/controller/ExpressionResolverImpl.java index efbdc36e36d..61b458e3baf 100644 --- a/controller/src/main/java/org/jboss/as/controller/ExpressionResolverImpl.java +++ b/controller/src/main/java/org/jboss/as/controller/ExpressionResolverImpl.java @@ -6,6 +6,7 @@ import java.util.Stack; +import org.jboss.as.controller.capability.CapabilityServiceSupport; import org.jboss.as.controller.logging.ControllerLogger; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; @@ -45,24 +46,31 @@ protected ExpressionResolverImpl(boolean lenient) { } @Override - public final ModelNode resolveExpressions(final ModelNode node) throws OperationFailedException { - return resolveExpressions(node, null); + public ModelNode resolveExpressions(final ModelNode node) throws OperationFailedException { + return resolveExpressions(node, (OperationContext) null); } @Override public ModelNode resolveExpressions(ModelNode node, OperationContext context) throws OperationFailedException { - return resolveExpressionsRecursively(node, context); + return resolveExpressionsRecursively(node, context, null); + } + + @Override + public ModelNode resolveExpressions(ModelNode node, CapabilityServiceSupport capabilityServiceSupport) throws OperationFailedException { + return resolveExpressionsRecursively(node, null, capabilityServiceSupport); } /** * Examine the given model node, resolving any expressions found within, including within child nodes. * * @param node the node - * @param context the {@link OperationContext} + * @param context any {@link OperationContext}. May be {@code null}. + * @param capabilitySupport any {@link CapabilityServiceSupport}. May be {@code null}. * @return a node with all expressions resolved * @throws OperationFailedException if an expression cannot be resolved */ - private ModelNode resolveExpressionsRecursively(final ModelNode node, final OperationContext context) throws OperationFailedException { + private ModelNode resolveExpressionsRecursively(final ModelNode node, final OperationContext context, + final CapabilityServiceSupport capabilitySupport) throws OperationFailedException { if (!node.isDefined()) { return node; } @@ -70,23 +78,25 @@ private ModelNode resolveExpressionsRecursively(final ModelNode node, final Oper ModelType type = node.getType(); ModelNode resolved; if (type == ModelType.EXPRESSION) { - resolved = resolveExpressionStringRecursively(node.asExpression().getExpressionString(), lenient, true, context); + resolved = resolveExpressionStringRecursively(node.asExpression().getExpressionString(), + lenient, true, context, capabilitySupport); } else if (type == ModelType.OBJECT) { resolved = node.clone(); for (Property prop : resolved.asPropertyList()) { - resolved.get(prop.getName()).set(resolveExpressionsRecursively(prop.getValue(), context)); + resolved.get(prop.getName()).set(resolveExpressionsRecursively(prop.getValue(), context, capabilitySupport)); } } else if (type == ModelType.LIST) { resolved = node.clone(); ModelNode list = new ModelNode(); list.setEmptyList(); for (ModelNode current : resolved.asList()) { - list.add(resolveExpressionsRecursively(current, context)); + list.add(resolveExpressionsRecursively(current, context, capabilitySupport)); } resolved = list; } else if (type == ModelType.PROPERTY) { resolved = node.clone(); - resolved.set(resolved.asProperty().getName(), resolveExpressionsRecursively(resolved.asProperty().getValue(), context)); + resolved.set(resolved.asProperty().getName(), + resolveExpressionsRecursively(resolved.asProperty().getValue(), context, capabilitySupport)); } else { resolved = node; } @@ -113,6 +123,30 @@ private ModelNode resolveExpressionsRecursively(final ModelNode node, final Oper protected void resolvePluggableExpression(ModelNode node, OperationContext context) throws OperationFailedException { } + /** + * Attempt to resolve the expression {@link org.jboss.dmr.ModelNode#asString() encapsulated in the given node}, + * setting the value of {@code node} to the resolved string if successful, or leaving {@code node} unaltered + * if the expression is not of a form resolvable by this method. When this method returns, the type of {@code node} + * should either be {@link ModelType#STRING} if this method was able to resolve, or {@link ModelType#EXPRESSION} if + * not. + *

+ * The default implementation simply calls the {@link #resolvePluggableExpression(ModelNode, OperationContext)} variant. + *

+ * + * @param node a node of type {@link ModelType#EXPRESSION} + * @param context the current {@link OperationContext}, if any. May be {@code null} + * @param capabilitySupport support object for resolving capability-based APIs. May be {@code null} + * + * @throws OperationFailedException if the expression in {@code node} is of a form that should be resolvable by this + * method but some resolution failure occurs + */ + protected void resolvePluggableExpression(ModelNode node, OperationContext context, CapabilityServiceSupport capabilitySupport) throws OperationFailedException { + // For compatibility, just call the older method. Subclasses can override this. + if (context != null) { + resolvePluggableExpression(node, context); + } + } + /** * Attempt to resolve the given expression string, recursing if resolution of one string produces * another expression. @@ -129,13 +163,14 @@ protected void resolvePluggableExpression(ModelNode node, OperationContext conte * @throws OperationFailedException if the expression cannot be resolved */ private ModelNode resolveExpressionStringRecursively(final String expressionString, final boolean ignoreDMRResolutionFailure, - final boolean initial, final OperationContext context) throws OperationFailedException { - ParseAndResolveResult resolved = parseAndResolve(expressionString, ignoreDMRResolutionFailure, context); + final boolean initial, final OperationContext context, + final CapabilityServiceSupport capabilitySupport) throws OperationFailedException { + ParseAndResolveResult resolved = parseAndResolve(expressionString, ignoreDMRResolutionFailure, context, capabilitySupport); if (resolved.recursive) { // Some part of expressionString resolved into a different expression. // So, start over, ignoring failures. Ignore failures because we don't require // that expressions must not resolve to something that *looks like* an expression but isn't - return resolveExpressionStringRecursively(resolved.result, true, false, context); + return resolveExpressionStringRecursively(resolved.result, true, false, context, capabilitySupport); } else if (resolved.modified) { // Typical case return new ModelNode(resolved.result); @@ -155,7 +190,8 @@ private ModelNode resolveExpressionStringRecursively(final String expressionStri } } - private ParseAndResolveResult parseAndResolve(final String initialValue, boolean lenient, OperationContext context) throws OperationFailedException { + private ParseAndResolveResult parseAndResolve(final String initialValue, boolean lenient, + OperationContext context, CapabilityServiceSupport capabilitySupport) throws OperationFailedException { final StringBuilder builder = new StringBuilder(); @@ -233,7 +269,7 @@ private ParseAndResolveResult parseAndResolve(final String initialValue, boolean continue; } String toResolve = getStringToResolve(initialValue, stack, i); - final String resolved = resolveExpressionString(toResolve, context); // TODO we could catch OFE or ERUE here + final String resolved = resolveExpressionString(toResolve, context, capabilitySupport); // TODO we could catch OFE or ERUE here // and if lenient respond with // the initial value, else rethrow // But for now it's a corner case @@ -317,7 +353,8 @@ private static Stack addToStack(Stack stack, int } /** Resolve the given string using any plugin and the DMR resolve method */ - private String resolveExpressionString(final String unresolvedString, final OperationContext context) throws OperationFailedException { + private String resolveExpressionString(final String unresolvedString, final OperationContext context, + final CapabilityServiceSupport capabilitySupport) throws OperationFailedException { // parseAndResolve should only be providing expressions with no leading or trailing chars assert unresolvedString.startsWith("${") && unresolvedString.endsWith("}"); @@ -328,7 +365,7 @@ private String resolveExpressionString(final String unresolvedString, final Oper ModelNode resolveNode = new ModelNode(new ValueExpression(unresolvedString)); // Try plug-in resolution; i.e. vault - resolvePluggableExpression(resolveNode, context); + resolvePluggableExpression(resolveNode, context, capabilitySupport); if (resolveNode.getType() == ModelType.EXPRESSION ) { // resolvePluggableExpression did nothing. Try standard resolution 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 06ce4f6ebc3..ffaec0febe9 100644 --- a/controller/src/main/java/org/jboss/as/controller/OperationContextImpl.java +++ b/controller/src/main/java/org/jboss/as/controller/OperationContextImpl.java @@ -43,7 +43,6 @@ import java.util.IdentityHashMap; import java.util.Iterator; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -1713,7 +1712,7 @@ private void rejectUserDomainServerUpdates() { public CapabilityServiceSupport getCapabilityServiceSupport() { assert isControllingThread(); assertCapabilitiesAvailable(currentStage); - return new CapabilityServiceSupportImpl(managementModel); + return new DefaultCapabilityServiceSupport(managementModel.getCapabilityRegistry()); } @Override @@ -2607,69 +2606,6 @@ private static class BooleanHolder { private boolean done = false; } - private static class CapabilityServiceSupportImpl implements CapabilityServiceSupport { - private final ManagementModel managementModel; - - private CapabilityServiceSupportImpl(ManagementModel managementModel) { - this.managementModel = managementModel; - } - - @Override - public boolean hasCapability(String capabilityName) { - return managementModel.getCapabilityRegistry().hasCapability(capabilityName, CapabilityScope.GLOBAL); - } - - @Override - public T getCapabilityRuntimeAPI(String capabilityName, Class apiType) throws NoSuchCapabilityException { - try { - return managementModel.getCapabilityRegistry().getCapabilityRuntimeAPI(capabilityName, CapabilityScope.GLOBAL, apiType); - } catch (IllegalStateException e) { - throw new NoSuchCapabilityException(capabilityName); - } - } - - @Override - public T getCapabilityRuntimeAPI(String capabilityBaseName, String dynamicPart, Class apiType) throws NoSuchCapabilityException { - String fullName = RuntimeCapability.buildDynamicCapabilityName(capabilityBaseName, dynamicPart); - return getCapabilityRuntimeAPI(fullName, apiType); - } - - @Override - public Optional getOptionalCapabilityRuntimeAPI(String capabilityName, Class apiType) { - try { - return Optional.of(getCapabilityRuntimeAPI(capabilityName, apiType)); - } catch (NoSuchCapabilityException e) { - return Optional.empty(); - } - } - - @Override - public Optional getOptionalCapabilityRuntimeAPI(String capabilityBaseName, String dynamicPart, Class apiType) { - try { - return Optional.of(getCapabilityRuntimeAPI(capabilityBaseName, dynamicPart, apiType)); - } catch (NoSuchCapabilityException e) { - return Optional.empty(); - } - } - - @Override - public ServiceName getCapabilityServiceName(String capabilityName) { - try { - return managementModel.getCapabilityRegistry().getCapabilityServiceName(capabilityName, CapabilityScope.GLOBAL, null); - } catch (IllegalStateException | IllegalArgumentException ignore) { - // ignore - } - ControllerLogger.ROOT_LOGGER.debugf("CapabilityServiceSupport: Parsing ServiceName for %s", capabilityName); - return ServiceNameFactory.parseServiceName(capabilityName); - } - - @Override - public ServiceName getCapabilityServiceName(String capabilityBaseName, String ... dynamicPart) { - ServiceName name = getCapabilityServiceName(capabilityBaseName); - return (dynamicPart.length > 0) ? name.append(dynamicPart) : name; - } - } - private static class CapabilityServiceBuilderImpl extends DelegatingServiceBuilder implements CapabilityServiceBuilder { private final PathAddress targetAddress; 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 22186fea5e3..a35a24ee75a 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 @@ -53,7 +53,7 @@ public NoSuchCapabilityException(String message) { * 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} + * @param 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) { diff --git a/controller/src/main/java/org/jboss/as/controller/extension/ExpressionResolverExtension.java b/controller/src/main/java/org/jboss/as/controller/extension/ExpressionResolverExtension.java index cddf0a08aa0..54cf45c2063 100644 --- a/controller/src/main/java/org/jboss/as/controller/extension/ExpressionResolverExtension.java +++ b/controller/src/main/java/org/jboss/as/controller/extension/ExpressionResolverExtension.java @@ -11,6 +11,7 @@ import org.jboss.as.controller.OperationClientException; import org.jboss.as.controller.OperationContext; import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.capability.CapabilityServiceSupport; /** * Object that can be used to extend the functionality of an {@link ExpressionResolver} by handling @@ -70,4 +71,24 @@ public interface ExpressionResolverExtension { */ String resolveExpression(String expression, OperationContext context); + /** + * Resolve a given simple expression string, returning {@code null} if the string is not of a form + * recognizable to the plugin. + * + * @param expression a string that matches {@link #EXTENSION_EXPRESSION_PATTERN} and that does not have + * any substrings that match that pattern. + * @param capabilitySupport object for accessing capability-backed APIs + * + * @throws ExpressionResolver.ExpressionResolutionUserException if {@code expression} is a form understood by the plugin but in some + * way is unacceptable. This should only be thrown due to flaws in the + * provided {@code expression} or the configuration of resources used by + * the resolver extension, which are 'user' problems. It should not + * be used for internal problems in the resolver extension. + * @throws ExpressionResolver.ExpressionResolutionServerException if some other internal expression resolution failure occurs. + * @throws UnsupportedOperationException if this extension does not support resolution from a CapabilityServiceSupport capabilitySupport. + */ + default String resolveExpression(String expression, CapabilityServiceSupport capabilitySupport) { + throw new UnsupportedOperationException(); + } + } diff --git a/controller/src/main/java/org/jboss/as/controller/extension/ExtensionRegistry.java b/controller/src/main/java/org/jboss/as/controller/extension/ExtensionRegistry.java index 9c01eaa60d5..571277aa133 100644 --- a/controller/src/main/java/org/jboss/as/controller/extension/ExtensionRegistry.java +++ b/controller/src/main/java/org/jboss/as/controller/extension/ExtensionRegistry.java @@ -57,6 +57,7 @@ import org.jboss.as.controller.access.management.JmxAuthorizer; import org.jboss.as.controller.audit.AuditLogger; import org.jboss.as.controller.audit.ManagedAuditLogger; +import org.jboss.as.controller.capability.CapabilityServiceSupport; import org.jboss.as.controller.capability.RuntimeCapability; import org.jboss.as.controller.descriptions.DescriptionProvider; import org.jboss.as.controller.descriptions.ModelDescriptionConstants; @@ -1422,5 +1423,16 @@ public String resolveExpression(String expression, OperationContext context) { } return null; } + + @Override + public String resolveExpression(String expression, CapabilityServiceSupport capabilitySupport) { + ExpressionResolverExtension delegate = delegateSupplier.get(); + if (delegate != null) { + return delegate.resolveExpression(expression, capabilitySupport); + } else if (expressionPattern.matcher(expression).matches()){ + throw ControllerLogger.ROOT_LOGGER.cannotResolveExpression(expression); + } + return null; + } } } diff --git a/elytron/src/main/java/org/wildfly/extension/elytron/expression/DeploymentExpressionResolverProcessor.java b/elytron/src/main/java/org/wildfly/extension/elytron/expression/DeploymentExpressionResolverProcessor.java index 60eb1eb5846..09963b5193d 100644 --- a/elytron/src/main/java/org/wildfly/extension/elytron/expression/DeploymentExpressionResolverProcessor.java +++ b/elytron/src/main/java/org/wildfly/extension/elytron/expression/DeploymentExpressionResolverProcessor.java @@ -24,7 +24,7 @@ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitPro CapabilityServiceSupport serviceSupport = deploymentUnit.getAttachment(Attachments.CAPABILITY_SERVICE_SUPPORT); try { final ElytronExpressionResolver resolver = serviceSupport.getCapabilityRuntimeAPI("org.wildfly.security.expression-resolver", ElytronExpressionResolver.class); - deploymentUnit.addToAttachmentList(Attachments.DEPLOYMENT_EXPRESSION_RESOLVERS, (s) -> resolver.resolveDeploymentExpression(s, serviceSupport)); + deploymentUnit.addToAttachmentList(Attachments.DEPLOYMENT_EXPRESSION_RESOLVERS, (s) -> resolver.resolveExpression(s, serviceSupport)); } catch (CapabilityServiceSupport.NoSuchCapabilityException e) { // /subsystem=elytron/expression=encryption resource is not present, so there's nothing to do. } diff --git a/elytron/src/main/java/org/wildfly/extension/elytron/expression/ElytronExpressionResolver.java b/elytron/src/main/java/org/wildfly/extension/elytron/expression/ElytronExpressionResolver.java index 0578cfc523a..ce4a17acc69 100644 --- a/elytron/src/main/java/org/wildfly/extension/elytron/expression/ElytronExpressionResolver.java +++ b/elytron/src/main/java/org/wildfly/extension/elytron/expression/ElytronExpressionResolver.java @@ -65,15 +65,10 @@ public String resolveExpression(String expression, OperationContext context) { return resolveExpressionInternal(expression, context, null); } - /** - * Resolves expressions found in deployment resources. - * - * @param expression the expression string. Cannot be {@code null} - * @param serviceSupport support object to use to resolve the needed {@link CredentialStore}. Cannot be {@code null} - * @return the resolved expression string or {@code null} if {@code expression} isn't a credential store expression - * or 'looks like' one but doesn't use the prefix supported by this resolver. - */ - String resolveDeploymentExpression(String expression, CapabilityServiceSupport serviceSupport) { + @Override + public String resolveExpression(String expression, CapabilityServiceSupport serviceSupport) { + checkNotNullParam("expression", expression); + checkNotNullParam("serviceSupport", serviceSupport); return resolveExpressionInternal(expression, null, serviceSupport); } diff --git a/host-controller/src/main/java/org/jboss/as/domain/controller/operations/SyncServerStateOperationHandler.java b/host-controller/src/main/java/org/jboss/as/domain/controller/operations/SyncServerStateOperationHandler.java index 00b16a2dee6..3de6dcb4e33 100644 --- a/host-controller/src/main/java/org/jboss/as/domain/controller/operations/SyncServerStateOperationHandler.java +++ b/host-controller/src/main/java/org/jboss/as/domain/controller/operations/SyncServerStateOperationHandler.java @@ -109,12 +109,16 @@ public void execute(OperationContext context, ModelNode operation) { ManagedServerBootConfiguration startConfig = new ManagedServerBootCmdFactory(serverName, startRoot, startHostModel, parameters.getHostControllerEnvironment(), - parameters.getDomainController().getExpressionResolver(), false).createConfiguration(); + parameters.getDomainController().getExpressionResolver(), + parameters.getDomainController().getCapabilityRegistry(), + false).createConfiguration(); ManagedServerBootConfiguration endConfig = new ManagedServerBootCmdFactory(serverName, endRoot, endHostModel, parameters.getHostControllerEnvironment(), - parameters.getDomainController().getExpressionResolver(), false).createConfiguration(); + parameters.getDomainController().getExpressionResolver(), + parameters.getDomainController().getCapabilityRegistry(), + false).createConfiguration(); if (startConfig == null || !startConfig.compareServerLaunchCommand(endConfig)) { servers.put(serverName, SyncServerResultAction.RESTART_REQUIRED); } diff --git a/host-controller/src/main/java/org/jboss/as/host/controller/ManagedServerBootCmdFactory.java b/host-controller/src/main/java/org/jboss/as/host/controller/ManagedServerBootCmdFactory.java index bf773df41bd..d078685321a 100644 --- a/host-controller/src/main/java/org/jboss/as/host/controller/ManagedServerBootCmdFactory.java +++ b/host-controller/src/main/java/org/jboss/as/host/controller/ManagedServerBootCmdFactory.java @@ -36,10 +36,13 @@ import javax.net.ssl.SSLContext; import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.DefaultCapabilityServiceSupport; import org.jboss.as.controller.ExpressionResolver; import org.jboss.as.controller.ExpressionResolverImpl; import org.jboss.as.controller.OperationContext; import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.capability.CapabilityServiceSupport; +import org.jboss.as.controller.capability.registry.ImmutableCapabilityRegistry; import org.jboss.as.domain.controller.resources.ServerGroupResourceDefinition; import org.jboss.as.host.controller.jvm.JvmType; import org.jboss.as.host.controller.model.host.HostResourceDefinition; @@ -117,12 +120,13 @@ private static Set getExcludedHostProperties() { public ManagedServerBootCmdFactory(final String serverName, final ModelNode domainModel, final ModelNode hostModel, final HostControllerEnvironment environment, final ExpressionResolver expressionResolver, - final boolean suspend) { + final ImmutableCapabilityRegistry capabilityRegistry, final boolean suspend) { this.serverName = serverName; this.domainModel = domainModel; this.hostModel = hostModel; this.environment = environment; - this.expressionResolver = new ManagedServerExprResolver(expressionResolver, this.serverName); + this.expressionResolver = new ManagedServerExprResolver(expressionResolver, this.serverName, + new DefaultCapabilityServiceSupport(capabilityRegistry)); this.suspend = suspend; this.serverModel = resolveExpressions(hostModel.require(SERVER_CONFIG).require(serverName), this.expressionResolver, true); this.directoryGrouping = resolveDirectoryGrouping(hostModel, this.expressionResolver); @@ -615,12 +619,14 @@ private static Map parseLaunchProperties(final List comm static class ManagedServerExprResolver extends ExpressionResolverImpl { final ExpressionResolver delegate; final String serverName; + final CapabilityServiceSupport capabilityServiceSupport; final Map resolvableData; - public ManagedServerExprResolver(ExpressionResolver delegate, String serverName) { + public ManagedServerExprResolver(ExpressionResolver delegate, String serverName, CapabilityServiceSupport capabilityServiceSupport) { super(true); this.delegate = delegate; this.serverName = serverName; + this.capabilityServiceSupport = capabilityServiceSupport; this.resolvableData = new HashMap<>() {{ put(ServerEnvironment.SERVER_BASE_DIR, null); put(ServerEnvironment.SERVER_DATA_DIR, null); @@ -631,7 +637,12 @@ public ManagedServerExprResolver(ExpressionResolver delegate, String serverName) } @Override - protected void resolvePluggableExpression(ModelNode node, OperationContext context) throws OperationFailedException { + public ModelNode resolveExpressions(final ModelNode node) throws OperationFailedException { + return resolveExpressions(node, capabilityServiceSupport); + } + + @Override + protected void resolvePluggableExpression(ModelNode node, OperationContext context, CapabilityServiceSupport capabilityServiceSupport) throws OperationFailedException { String expression = node.asString(); if (expression.length() > 3) { String expressionValue = expression.substring(2, expression.length() - 1); @@ -641,7 +652,7 @@ protected void resolvePluggableExpression(ModelNode node, OperationContext conte node.set(resolved); } } else { - node.set(delegate.resolveExpressions(node, context)); + node.set(delegate.resolveExpressions(node, capabilityServiceSupport)); } } } diff --git a/host-controller/src/main/java/org/jboss/as/host/controller/ManagedServerOperationsFactory.java b/host-controller/src/main/java/org/jboss/as/host/controller/ManagedServerOperationsFactory.java index d2428128b6a..66c30d14268 100644 --- a/host-controller/src/main/java/org/jboss/as/host/controller/ManagedServerOperationsFactory.java +++ b/host-controller/src/main/java/org/jboss/as/host/controller/ManagedServerOperationsFactory.java @@ -94,6 +94,7 @@ import java.util.Set; import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.DefaultCapabilityServiceSupport; import org.jboss.as.controller.ExpressionResolver; import org.jboss.as.controller.OperationFailedException; import org.jboss.as.controller.PathAddress; @@ -105,6 +106,8 @@ import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CONFIGURED_REQUIRES_READ; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CONFIGURED_REQUIRES_WRITE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.TYPE; + +import org.jboss.as.controller.capability.CapabilityServiceSupport; import org.jboss.as.controller.operations.common.NamespaceAddHandler; import org.jboss.as.controller.operations.common.SchemaLocationAddHandler; import org.jboss.as.server.services.net.SocketBindingAddHandler; @@ -184,7 +187,9 @@ public static ModelNode createBootUpdates(final String serverName, final ModelNo this.domainModel = domainModel; this.hostModel = hostModel; this.domainController = domainController; - ManagedServerBootCmdFactory.ManagedServerExprResolver managedServerExpResolver = new ManagedServerBootCmdFactory.ManagedServerExprResolver(expressionResolver, this.serverName); + CapabilityServiceSupport capabilityServiceSupport = new DefaultCapabilityServiceSupport(domainController.getCapabilityRegistry()); + ManagedServerBootCmdFactory.ManagedServerExprResolver managedServerExpResolver = + new ManagedServerBootCmdFactory.ManagedServerExprResolver(expressionResolver, this.serverName, capabilityServiceSupport); this.serverModel = resolveExpressions(hostModel.require(SERVER_CONFIG).require(serverName), managedServerExpResolver, true); this.serverGroupName = serverModel.require(GROUP).asString(); diff --git a/host-controller/src/main/java/org/jboss/as/host/controller/ServerInventoryImpl.java b/host-controller/src/main/java/org/jboss/as/host/controller/ServerInventoryImpl.java index 565499cccbc..6be1f0335f2 100644 --- a/host-controller/src/main/java/org/jboss/as/host/controller/ServerInventoryImpl.java +++ b/host-controller/src/main/java/org/jboss/as/host/controller/ServerInventoryImpl.java @@ -761,7 +761,8 @@ public boolean validateServerEvidence(Evidence evidence) { private ManagedServerBootCmdFactory createBootFactory(final String serverName, final ModelNode domainModel, boolean suspend) { final String hostControllerName = domainController.getLocalHostInfo().getLocalHostName(); final ModelNode hostModel = domainModel.require(HOST).require(hostControllerName); - return new ManagedServerBootCmdFactory(serverName, domainModel, hostModel, environment, domainController.getExpressionResolver(), suspend); + return new ManagedServerBootCmdFactory(serverName, domainModel, hostModel, environment, + domainController.getExpressionResolver(), domainController.getCapabilityRegistry(), suspend); } private ModelNode appendServerNameToFailureResponse(String serverName, ModelNode failureResponse) { diff --git a/host-controller/src/test/java/org/jboss/as/host/controller/ManagedServerBootCmdFactoryTestCase.java b/host-controller/src/test/java/org/jboss/as/host/controller/ManagedServerBootCmdFactoryTestCase.java index dceeb240d10..566f91b9e30 100644 --- a/host-controller/src/test/java/org/jboss/as/host/controller/ManagedServerBootCmdFactoryTestCase.java +++ b/host-controller/src/test/java/org/jboss/as/host/controller/ManagedServerBootCmdFactoryTestCase.java @@ -23,6 +23,7 @@ import java.util.Map; import org.hamcrest.MatcherAssert; +import org.jboss.as.controller.CapabilityRegistry; import org.jboss.as.controller.ExpressionResolver; import org.jboss.as.controller.RunningMode; import org.jboss.as.version.ProductConfig; @@ -104,7 +105,9 @@ private static ModelNode getDomainModel() { @Test public void testCreateConfiguration() throws UnknownHostException { System.out.println("createConfiguration"); - ManagedServerBootCmdFactory instance = new ManagedServerBootCmdFactory("test-server", getDomainModel(), getHostModel(), getTestHostEnvironment(), ExpressionResolver.TEST_RESOLVER, false); + ManagedServerBootCmdFactory instance = new ManagedServerBootCmdFactory("test-server", getDomainModel(), + getHostModel(), getTestHostEnvironment(), ExpressionResolver.TEST_RESOLVER, + new CapabilityRegistry(false), false); ManagedServerBootConfiguration result = instance.createConfiguration(); Assert.assertNotNull(result); } @@ -120,7 +123,9 @@ private static int getJavaVersion() { @Test public void testGetServerLaunchCommand() throws UnknownHostException { System.out.println("getServerLaunchCommand"); - ManagedServerBootCmdFactory instance = new ManagedServerBootCmdFactory("test-server", getDomainModel(), getHostModel(), getTestHostEnvironment(), ExpressionResolver.TEST_RESOLVER, false); + ManagedServerBootCmdFactory instance = new ManagedServerBootCmdFactory("test-server", getDomainModel(), + getHostModel(), getTestHostEnvironment(), ExpressionResolver.TEST_RESOLVER, + new CapabilityRegistry(false), false); List result = instance.getServerLaunchCommand(); MatcherAssert.assertThat(result.size(), is(notNullValue())); if (result.size() > 18) { diff --git a/server/src/main/java/org/jboss/as/server/RuntimeExpressionResolver.java b/server/src/main/java/org/jboss/as/server/RuntimeExpressionResolver.java index 81a5cea5782..5ceffe31466 100644 --- a/server/src/main/java/org/jboss/as/server/RuntimeExpressionResolver.java +++ b/server/src/main/java/org/jboss/as/server/RuntimeExpressionResolver.java @@ -8,6 +8,7 @@ import java.util.Iterator; import java.util.Set; +import org.jboss.as.controller.capability.CapabilityServiceSupport; import org.jboss.as.controller.extension.ExpressionResolverExtension; import org.jboss.as.controller.ExpressionResolverImpl; import org.jboss.as.controller.OperationClientException; @@ -41,8 +42,13 @@ public synchronized void removeResolverExtension(ExpressionResolverExtension ext @Override protected void resolvePluggableExpression(ModelNode node, OperationContext context) throws OperationFailedException { + resolvePluggableExpression(node, context, null); + } + + @Override + protected void resolvePluggableExpression(ModelNode node, OperationContext context, CapabilityServiceSupport capabilitySupport) throws OperationFailedException { String expression = node.asString(); - if (context != null && expression.length() > 3) { + if ((context != null || capabilitySupport != null) && expression.length() > 3) { // Cycle through all registered extensions until one returns a result. // Cache any exceptions (first of each type) so we can propagate them @@ -56,7 +62,7 @@ protected void resolvePluggableExpression(ModelNode node, OperationContext conte Iterator iter = extensions.iterator(); while (result == null && iter.hasNext()) { try { - result = resolveExpression(expression, iter.next(), context); + result = resolveExpression(expression, iter.next(), context, capabilitySupport); } catch (OperationFailedException oe) { if (ofe == null) { ofe = oe; @@ -88,8 +94,17 @@ protected void resolvePluggableExpression(ModelNode node, OperationContext conte } } - private String resolveExpression(String expression, ExpressionResolverExtension resolver, OperationContext context) throws OperationFailedException { - resolver.initialize(context); - return resolver.resolveExpression(expression, context); + private String resolveExpression(String expression, ExpressionResolverExtension resolver, OperationContext context, + CapabilityServiceSupport capabilitySupport) throws OperationFailedException { + if (context != null) { + resolver.initialize(context); + return resolver.resolveExpression(expression, context); + } else { + try { + return resolver.resolveExpression(expression, capabilitySupport); + } catch (UnsupportedOperationException uoe) { + return null; + } + } } }