Skip to content

Commit

Permalink
[WFCORE-7087] Support resolution of extension expressions during prep…
Browse files Browse the repository at this point in the history
…aration of a domain server launch command
  • Loading branch information
bstansberry committed Jan 12, 2025
1 parent 55e18a0 commit 40d9839
Show file tree
Hide file tree
Showing 18 changed files with 534 additions and 126 deletions.
Original file line number Diff line number Diff line change
@@ -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> T getCapabilityRuntimeAPI(String capabilityName, Class<T> apiType) throws NoSuchCapabilityException {
try {
return registry.getCapabilityRuntimeAPI(capabilityName, CapabilityScope.GLOBAL, apiType);
} catch (IllegalStateException e) {
throw new NoSuchCapabilityException(capabilityName);
}
}

@Override
public <T> T getCapabilityRuntimeAPI(String capabilityBaseName, String dynamicPart, Class<T> apiType) throws NoSuchCapabilityException {
String fullName = RuntimeCapability.buildDynamicCapabilityName(capabilityBaseName, dynamicPart);
return getCapabilityRuntimeAPI(fullName, apiType);
}

@Override
public <T> Optional<T> getOptionalCapabilityRuntimeAPI(String capabilityName, Class<T> apiType) {
try {
return Optional.of(getCapabilityRuntimeAPI(capabilityName, apiType));
} catch (NoSuchCapabilityException e) {
return Optional.empty();
}
}

@Override
public <T> Optional<T> getOptionalCapabilityRuntimeAPI(String capabilityBaseName, String dynamicPart, Class<T> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
* <p/>
* 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.
Expand All @@ -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.
* <p/>
* 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
Expand All @@ -75,6 +74,41 @@ default ModelNode resolveExpressions(ModelNode node, OperationContext context) t
return resolveExpressions(node);
}

/**
* Resolves any expressions in the passed-in ModelNode.
* <p/>
* 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 ExpressionResolver.ExpressionResolutionServerException if some other internal expression resolution failure occurs.
*/
default ModelNode resolveExpressions(ModelNode node, CapabilityServiceSupport capabilitySupport) {
try {
return resolveExpressions(node);
} catch (OperationFailedException e) {
// This can be thrown because supposedly an ExpressionResolverExtension could throw
// it from ExpressionResolverExtension.initialize(OperationContext). But per the initialize()
// javadoc it should only do that in response to a user problem determined by using the OperationContext.
// But there is no OperationContext passed in a call to resolveExpressions(ModelNode)!
// That method should remove 'throws OperationFailedException', but that would be a breaking API change.
// So this shouldn't happen and if it does something has gone wrong
throw new IllegalStateException(e);
}
}

/**
* 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
Expand Down
Loading

0 comments on commit 40d9839

Please sign in to comment.