Skip to content

Commit

Permalink
WFCORE-6663 Add new AttributeDefinition implementations that resolves…
Browse files Browse the repository at this point in the history
… a model directly to a ServiceDependency.
  • Loading branch information
pferraro committed Sep 11, 2024
1 parent e03ace6 commit d2ea532
Show file tree
Hide file tree
Showing 13 changed files with 1,113 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,25 @@

import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.registry.Resource;
import org.jboss.dmr.ModelNode;

/**
* Resolves a value from a resource model.
*/
public interface ResourceModelResolver<T> {

/**
* Resolves a value from the specified resource, using the specified operation context.
* @param context an operation context
* @param resource a resource
* @return the resolved value
* @throws OperationFailedException if the value could not be resolved
*/
default T resolve(OperationContext context, Resource resource) throws OperationFailedException {
return this.resolve(context, resource.getModel());
}

/**
* Resolves a value from the specified resource model, using the specified operation context.
* @param context an operation context
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/

package org.wildfly.subsystem.resource;

import java.util.Set;

import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.registry.Resource;
import org.jboss.dmr.ModelNode;

/**
* A resource facade for an existing resource model, i.e. with no children
*/
public class SimpleResource implements Resource {
private final ModelNode model;

public SimpleResource(ModelNode model) {
this.model = model;
}

@Override
public ModelNode getModel() {
return this.model;
}

@Override
public void writeModel(ModelNode newModel) {
throw new UnsupportedOperationException();
}

@Override
public boolean isModelDefined() {
return this.model.isDefined();
}

@Override
public boolean hasChild(PathElement element) {
return false;
}

@Override
public Resource getChild(PathElement element) {
return null;
}

@Override
public Resource requireChild(PathElement element) {
throw new NoSuchResourceException(element);
}

@Override
public boolean hasChildren(String childType) {
return false;
}

@Override
public Resource navigate(PathAddress address) {
if (address.size() == 0) return this;
throw new NoSuchResourceException(address.getElement(0));
}

@Override
public Set<String> getChildTypes() {
return Set.of();
}

@Override
public Set<String> getChildrenNames(String childType) {
return Set.of();
}

@Override
public Set<ResourceEntry> getChildren(String childType) {
return Set.of();
}

@Override
public void registerChild(PathElement address, Resource resource) {
throw new UnsupportedOperationException();
}

@Override
public void registerChild(PathElement address, int index, Resource resource) {
throw new UnsupportedOperationException();
}

@Override
public Resource removeChild(PathElement address) {
throw new UnsupportedOperationException();
}

@Override
public Set<String> getOrderedChildTypes() {
return Set.of();
}

@Override
public boolean isRuntime() {
return false;
}

@Override
public boolean isProxy() {
return false;
}

@Override
public Resource clone() {
return new SimpleResource(this.model.clone());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.function.Function;
import java.util.function.UnaryOperator;

Expand Down Expand Up @@ -53,7 +54,7 @@ default String getBaseDependentName() {
* @param requirement the requirement of the specified capability
*/
static <T> Builder<T> builder(RuntimeCapability<Void> capability, UnaryServiceDescriptor<T> requirement) {
return new DefaultBuilder<>(capability, requirement);
return new DefaultBuilder<>(capability, NaryServiceDescriptor.of(requirement));
}

/**
Expand All @@ -63,7 +64,7 @@ static <T> Builder<T> builder(RuntimeCapability<Void> capability, UnaryServiceDe
* @param requirement the requirement of the specified capability
*/
static <T> ParentPathProvider<T> builder(RuntimeCapability<Void> capability, BinaryServiceDescriptor<T> requirement) {
return new DefaultBuilder<>(capability, requirement);
return new DefaultBuilder<>(capability, NaryServiceDescriptor.of(requirement));
}

/**
Expand All @@ -73,7 +74,7 @@ static <T> ParentPathProvider<T> builder(RuntimeCapability<Void> capability, Bin
* @param requirement the requirement of the specified capability
*/
static <T> GrandparentPathProvider<T> builder(RuntimeCapability<Void> capability, TernaryServiceDescriptor<T> requirement) {
return new DefaultBuilder<>(capability, requirement);
return new DefaultBuilder<>(capability, NaryServiceDescriptor.of(requirement));
}

/**
Expand All @@ -83,7 +84,7 @@ static <T> GrandparentPathProvider<T> builder(RuntimeCapability<Void> capability
* @param requirement the requirement of the specified capability
*/
static <T> GreatGrandparentPathProvider<T> builder(RuntimeCapability<Void> capability, QuaternaryServiceDescriptor<T> requirement) {
return new DefaultBuilder<>(capability, requirement);
return new DefaultBuilder<>(capability, NaryServiceDescriptor.of(requirement));
}

interface Builder<T> {
Expand Down Expand Up @@ -188,11 +189,11 @@ class DefaultBuilder<T> implements GreatGrandparentPathProvider<T>, GrandparentP
private static final UnaryOperator<String> CHILD_REQUIREMENT_PATTERN_SEGMENT_RESOLVER = UnaryOperator.identity();

private final RuntimeCapability<Void> capability;
private final ServiceDescriptor<T> requirement;
private final NaryServiceDescriptor<T> requirement;
private final List<RequirementNameSegmentResolver> requirementNameSegmentResolvers = new ArrayList<>(4);
private final List<UnaryOperator<String>> requirementPatternSegmentResolvers= new ArrayList<>(4);

DefaultBuilder(RuntimeCapability<Void> capability, ServiceDescriptor<T> requirement) {
DefaultBuilder(RuntimeCapability<Void> capability, NaryServiceDescriptor<T> requirement) {
this.capability = capability;
this.requirement = requirement;
}
Expand Down Expand Up @@ -244,7 +245,7 @@ private static RequirementNameSegmentResolver createRequirementNameSegmentResolv
@Override
public String resolve(OperationContext context, Resource resource, String value) {
try {
return attribute.resolveModelAttribute(context, resource.getModel()).asString();
return attribute.resolveModelAttribute(context, resource.getModel()).asStringOrNull();
} catch (OperationFailedException e) {
throw new IllegalArgumentException(e);
}
Expand Down Expand Up @@ -290,9 +291,9 @@ public CapabilityReference<T> build() {
abstract class AbstractServiceDescriptorReference<T> implements CapabilityReference<T> {

private final RuntimeCapability<Void> capability;
private final ServiceDescriptor<T> requirement;
private final NaryServiceDescriptor<T> requirement;

AbstractServiceDescriptorReference(RuntimeCapability<Void> capability, ServiceDescriptor<T> requirement) {
AbstractServiceDescriptorReference(RuntimeCapability<Void> capability, NaryServiceDescriptor<T> requirement) {
this.capability = capability;
this.requirement = requirement;
}
Expand All @@ -303,7 +304,7 @@ public RuntimeCapability<Void> getDependent() {
}

@Override
public ServiceDescriptor<T> getRequirement() {
public NaryServiceDescriptor<T> getRequirement() {
return this.requirement;
}

Expand All @@ -327,20 +328,20 @@ class ServiceDescriptorReference<T> extends AbstractServiceDescriptorReference<T
private final List<RequirementNameSegmentResolver> requirementNameSegmentResolvers;
private final List<UnaryOperator<String>> requirementPatternSegmentResolvers;

ServiceDescriptorReference(RuntimeCapability<Void> capability, ServiceDescriptor<T> requirement, List<RequirementNameSegmentResolver> requirementNameSegmentResolvers, List<UnaryOperator<String>> requirementPatternSegmentResolvers) {
ServiceDescriptorReference(RuntimeCapability<Void> capability, NaryServiceDescriptor<T> requirement, List<RequirementNameSegmentResolver> requirementNameSegmentResolvers, List<UnaryOperator<String>> requirementPatternSegmentResolvers) {
super(capability, requirement);
this.requirementNameSegmentResolvers = List.copyOf(requirementNameSegmentResolvers);
this.requirementPatternSegmentResolvers = List.copyOf(requirementPatternSegmentResolvers);
}

@Override
public String[] resolve(OperationContext context, Resource resource, String value) {
public Map.Entry<String, String[]> resolve(OperationContext context, Resource resource, String value) {
String[] segments = new String[this.requirementNameSegmentResolvers.size()];
ListIterator<RequirementNameSegmentResolver> resolvers = this.requirementNameSegmentResolvers.listIterator();
while (resolvers.hasNext()) {
segments[resolvers.nextIndex()] = resolvers.next().resolve(context, resource, value);
}
return segments;
return this.getRequirement().resolve(segments);
}

@Override
Expand All @@ -366,7 +367,8 @@ public void removeCapabilityRequirements(OperationContext context, Resource reso
}

private String resolveRequirementName(OperationContext context, Resource resource, String value) {
return RuntimeCapability.buildDynamicCapabilityName(this.getBaseRequirementName(), this.resolve(context, resource, value));
Map.Entry<String, String[]> resolved = this.resolve(context, resource, value);
return (resolved.getValue().length > 0) ? RuntimeCapability.buildDynamicCapabilityName(resolved.getKey(), resolved.getValue()) : resolved.getKey();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/

package org.wildfly.subsystem.resource.capability;

import java.util.Map;

import org.jboss.as.controller.AbstractAttributeDefinitionBuilder;
import org.jboss.as.controller.AttributeParser;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.operations.validation.StringLengthValidator;
import org.jboss.as.controller.registry.AttributeAccess.Flag;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import org.wildfly.subsystem.resource.SimpleResource;
import org.wildfly.subsystem.resource.ResourceModelResolver;
import org.wildfly.subsystem.service.ServiceDependency;

/**
* An attribute definition referencing some capability.
* Resolves directly to a {@link ServiceDependency} via {@link #resolve(OperationContext, ModelNode)}.
*/
public class CapabilityReferenceAttributeDefinition<T> extends SimpleAttributeDefinition implements ResourceModelResolver<ServiceDependency<T>> {

private final CapabilityReferenceResolver<T> resolver;

CapabilityReferenceAttributeDefinition(Builder<T> builder) {
super(builder);
this.resolver = builder.resolver;
}

@Override
public ServiceDependency<T> resolve(OperationContext context, ModelNode model) throws OperationFailedException {
String value = this.resolveModelAttribute(context, model).asStringOrNull();
Map.Entry<String, String[]> resolved = this.resolver.resolve(context, new SimpleResource(model), value);
return (resolved != null) ? ServiceDependency.on(resolved.getKey(), this.resolver.getRequirement().getType(), resolved.getValue()) : ServiceDependency.of(null);
}

public static class Builder<T> extends AbstractAttributeDefinitionBuilder<Builder<T>, CapabilityReferenceAttributeDefinition<T>> {

final CapabilityReferenceResolver<T> resolver;

public Builder(String attributeName, CapabilityReference<T> reference) {
super(attributeName, ModelType.STRING);
// Capability references never allow expressions
this.setAllowExpression(false);
this.setAttributeParser(AttributeParser.SIMPLE);
this.setCapabilityReference(reference);
this.setFlags(Flag.RESTART_RESOURCE_SERVICES);
this.setValidator(new StringLengthValidator(1));
this.resolver = reference;
}

public Builder(String attributeName, CapabilityReferenceAttributeDefinition<T> basis) {
super(attributeName, basis);
this.resolver = basis.resolver;
}

@Override
public Builder<T> setDefaultValue(ModelNode defaultValue) {
// A capability reference must not specify a default value
if ((defaultValue != null) && defaultValue.isDefined()) {
throw new UnsupportedOperationException();
}
return this;
}

@Override
public Builder<T> setAllowExpression(boolean allowExpression) {
// A capability reference must not allow expressions
if (allowExpression) {
throw new UnsupportedOperationException();
}
return this;
}

@Override
public CapabilityReferenceAttributeDefinition<T> build() {
return new CapabilityReferenceAttributeDefinition<>(this);
}
}
}
Loading

0 comments on commit d2ea532

Please sign in to comment.