All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.as.clustering.controller.AddStepHandler Maven / Gradle / Ivy

Go to download

The code in this module is not explicitly related to clustering, but rather contains resuable code used by clustering modules and any modules that integrate with clustering.

There is a newer version: 34.0.0.Final
Show newest version
/*
 * Copyright The WildFly Authors
 * SPDX-License-Identifier: Apache-2.0
 */

package org.jboss.as.clustering.controller;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;

import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.CapabilityReferenceRecorder;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.OperationStepHandler;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.SimpleOperationDefinitionBuilder;
import org.jboss.as.controller.descriptions.DefaultResourceAddDescriptionProvider;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.logging.ControllerLogger;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.controller.registry.AttributeAccess;
import org.jboss.as.controller.registry.ImmutableManagementResourceRegistration;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.registry.OperationEntry;
import org.jboss.as.controller.registry.Resource;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;

/**
 * Generic add operation step handler that delegates service installation/rollback to a {@link ResourceServiceHandler}.
 * @author Paul Ferraro
 */
public class AddStepHandler extends AbstractAddStepHandler implements ManagementRegistrar, DescribedAddStepHandler {

    private final AddStepHandlerDescriptor descriptor;
    private final ResourceServiceHandler handler;

    public AddStepHandler(AddStepHandlerDescriptor descriptor) {
        this(descriptor, null);
    }

    public AddStepHandler(AddStepHandlerDescriptor descriptor, ResourceServiceHandler handler) {
        this.descriptor = descriptor;
        this.handler = handler;
    }

    @Override
    protected boolean requiresRuntime(OperationContext context) {
        return super.requiresRuntime(context) && (this.handler != null);
    }

    @Override
    public AddStepHandlerDescriptor getDescriptor() {
        return this.descriptor;
    }

    @Override
    public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
        PathAddress address = context.getCurrentAddress();
        PathAddress parentAddress = address.getParent();
        PathElement path = address.getLastElement();

        OperationStepHandler parentHandler = context.getRootResourceRegistration().getOperationHandler(parentAddress, ModelDescriptionConstants.ADD);
        if (parentHandler instanceof DescribedAddStepHandler) {
            AddStepHandlerDescriptor parentDescriptor = ((DescribedAddStepHandler) parentHandler).getDescriptor();

            if (parentDescriptor.getRequiredChildren().contains(path)) {
                if (context.readResourceFromRoot(parentAddress, false).hasChild(path)) {
                    // If we are a required child resource of our parent, we need to remove the auto-created resource first
                    context.addStep(Util.createRemoveOperation(address), context.getRootResourceRegistration().getOperationHandler(address, ModelDescriptionConstants.REMOVE), OperationContext.Stage.MODEL);
                    context.addStep(operation, this, OperationContext.Stage.MODEL);
                    return;
                }
            }
            for (PathElement requiredPath : parentDescriptor.getRequiredSingletonChildren()) {
                String requiredPathKey = requiredPath.getKey();
                if (requiredPath.getKey().equals(path.getKey())) {
                    Set childrenNames = context.readResourceFromRoot(parentAddress, false).getChildrenNames(requiredPathKey);
                    if (!childrenNames.isEmpty()) {
                        // If there is a required singleton sibling resource, we need to remove it first
                        for (String childName : childrenNames) {
                            PathAddress singletonAddress = parentAddress.append(requiredPathKey, childName);
                            context.addStep(Util.createRemoveOperation(singletonAddress), context.getRootResourceRegistration().getOperationHandler(singletonAddress, ModelDescriptionConstants.REMOVE), OperationContext.Stage.MODEL);
                        }
                        context.addStep(operation, this, OperationContext.Stage.MODEL);
                        return;
                    }
                }
            }
        }

        super.execute(context, operation);

        if (this.requiresRuntime(context)) {
            for (RuntimeResourceRegistration registration : this.descriptor.getRuntimeResourceRegistrations()) {
                context.addStep(new RuntimeResourceRegistrationStepHandler(registration), OperationContext.Stage.MODEL);
            }
        }
    }

    @Override
    protected Resource createResource(OperationContext context) {
        Resource resource = Resource.Factory.create(context.getResourceRegistration().isRuntimeOnly());
        if (context.isDefaultRequiresRuntime()) {
            resource = this.descriptor.getResourceTransformation().apply(resource);
        }
        context.addResource(PathAddress.EMPTY_ADDRESS, resource);
        return resource;
    }

    @Override
    protected Resource createResource(OperationContext context, ModelNode operation) {
        UnaryOperator transformation = context.isDefaultRequiresRuntime() ? this.descriptor.getResourceTransformation() : UnaryOperator.identity();
        ImmutableManagementResourceRegistration registration = context.getResourceRegistration();
        Resource resource = transformation.apply(Resource.Factory.create(registration.isRuntimeOnly(), registration.getOrderedChildTypes()));
        Integer index = registration.isOrderedChildResource() && operation.hasDefined(ModelDescriptionConstants.ADD_INDEX) ? operation.get(ModelDescriptionConstants.ADD_INDEX).asIntOrNull() : null;
        if (index == null) {
            context.addResource(PathAddress.EMPTY_ADDRESS, resource);
        } else {
            context.addResource(PathAddress.EMPTY_ADDRESS, index, resource);
        }
        return resource;
    }

    @Override
    protected void populateModel(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException {
        // Validate extra add operation parameters
        for (AttributeDefinition definition : this.descriptor.getExtraParameters()) {
            definition.validateOperation(operation);
        }
        PathAddress currentAddress = context.getCurrentAddress();
        // Validate and apply attribute translations
        Map translations = this.descriptor.getAttributeTranslations();
        for (Map.Entry entry : translations.entrySet()) {
            AttributeDefinition sourceParameter = entry.getKey();
            AttributeTranslation translation = entry.getValue();
            if (operation.hasDefined(sourceParameter.getName())) {
                ModelNode value = sourceParameter.validateOperation(operation);
                ModelNode targetValue = translation.getWriteTranslator().translate(context, value);
                Attribute targetAttribute = translation.getTargetAttribute();
                PathAddress targetAddress = translation.getPathAddressTransformation().apply(currentAddress);
                // If target attribute exists in the current resource, just fix the operation
                // Otherwise, we need a separate write-attribute operation
                if (targetAddress == currentAddress) {
                    String targetName = targetAttribute.getName();
                    if (!operation.hasDefined(targetName)) {
                        operation.get(targetName).set(targetValue);
                    }
                } else {
                    ModelNode writeAttributeOperation = Util.getWriteAttributeOperation(targetAddress, targetAttribute.getName(), targetValue);
                    ImmutableManagementResourceRegistration registration = (currentAddress == targetAddress) ? context.getResourceRegistration() : context.getRootResourceRegistration().getSubModel(targetAddress);
                    if (registration == null) {
                        throw new OperationFailedException(ControllerLogger.MGMT_OP_LOGGER.noSuchResourceType(targetAddress));
                    }
                    OperationStepHandler writeAttributeHandler = registration.getAttributeAccess(PathAddress.EMPTY_ADDRESS, targetAttribute.getName()).getWriteHandler();
                    context.addStep(writeAttributeOperation, writeAttributeHandler, OperationContext.Stage.MODEL);
                }
            }
        }
        // Validate proper attributes
        ModelNode model = resource.getModel();
        ImmutableManagementResourceRegistration registration = context.getResourceRegistration();
        for (String attributeName : registration.getAttributeNames(PathAddress.EMPTY_ADDRESS)) {
            AttributeAccess attribute = registration.getAttributeAccess(PathAddress.EMPTY_ADDRESS, attributeName);
            AttributeDefinition definition = attribute.getAttributeDefinition();
            if ((attribute.getStorageType() == AttributeAccess.Storage.CONFIGURATION) && !translations.containsKey(definition)) {
                OperationStepHandler writeHandler = this.descriptor.getCustomAttributes().get(definition);
                if (writeHandler != null) {
                    // If attribute has custom handling, perform a separate write-attribute operation
                    ModelNode writeAttributeOperation = Util.getWriteAttributeOperation(currentAddress, definition.getName(), definition.validateOperation(operation));
                    context.addStep(writeAttributeOperation, writeHandler, OperationContext.Stage.MODEL);
                } else {
                    definition.validateAndSet(operation, model);
                }
            }
        }

        // Auto-create required child resources as necessary
        addRequiredChildren(context, this.descriptor.getRequiredChildren(), (Resource parent, PathElement path) -> parent.hasChild(path));
        addRequiredChildren(context, this.descriptor.getRequiredSingletonChildren(), (Resource parent, PathElement path) -> parent.hasChildren(path.getKey()));

        // Don't leave model undefined
        if (!model.isDefined()) {
            model.setEmptyObject();
        }
    }

    private static void addRequiredChildren(OperationContext context, Collection paths, BiPredicate present) {
        for (PathElement path : paths) {
            context.addStep(Util.createAddOperation(context.getCurrentAddress().append(path)), new AddIfAbsentStepHandler(present), OperationContext.Stage.MODEL);
        }
    }

    @Override
    protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
        this.handler.installServices(context, model);
    }

    @Override
    protected void rollbackRuntime(OperationContext context, ModelNode operation, Resource resource) {
        try {
            this.handler.removeServices(context, resource.getModel());
        } catch (OperationFailedException e) {
            throw new IllegalStateException(e);
        }
    }

    @Override
    protected void recordCapabilitiesAndRequirements(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException {
        PathAddress address = context.getCurrentAddress();
        ModelNode model = resource.getModel();
        // The super implementation assumes that the capability name is a simple extension of the base name - we do not.
        // Only register capabilities when allowed by the associated predicate
        for (Map.Entry> entry : this.descriptor.getCapabilities().entrySet()) {
            if (entry.getValue().test(model)) {
                context.registerCapability(entry.getKey().resolve(address));
            }
        }

        ImmutableManagementResourceRegistration registration = context.getResourceRegistration();
        for (String attributeName : registration.getAttributeNames(PathAddress.EMPTY_ADDRESS)) {
            AttributeDefinition attribute = registration.getAttributeAccess(PathAddress.EMPTY_ADDRESS, attributeName).getAttributeDefinition();
            if (attribute.hasCapabilityRequirements()) {
                attribute.addCapabilityRequirements(context, resource, model.get(attributeName));
            }
        }

        for (CapabilityReferenceRecorder recorder : registration.getRequirements()) {
            recorder.addCapabilityRequirements(context, resource, null);
        }
    }

    @Override
    public void register(ManagementResourceRegistration registration) {
        SimpleOperationDefinitionBuilder builder = new SimpleOperationDefinitionBuilder(ModelDescriptionConstants.ADD, this.descriptor.getDescriptionResolver())
                .setDescriptionProvider(new DefaultResourceAddDescriptionProvider(registration, this.descriptor.getDescriptionResolver(), registration.isOrderedChildResource()))
                .withFlag(OperationEntry.Flag.RESTART_NONE)
                ;
        if (registration.isOrderedChildResource()) {
            builder.addParameter(SimpleAttributeDefinitionBuilder.create(ModelDescriptionConstants.ADD_INDEX, ModelType.INT, true).build());
        }
        for (AttributeDefinition attribute : this.descriptor.getAttributes()) {
            builder.addParameter(attribute);
        }
        for (AttributeDefinition attribute : this.descriptor.getCustomAttributes().keySet()) {
            builder.addParameter(attribute);
        }
        for (AttributeDefinition attribute : this.descriptor.getIgnoredAttributes()) {
            builder.addParameter(attribute);
        }
        for (AttributeDefinition parameter : this.descriptor.getExtraParameters()) {
            builder.addParameter(parameter);
        }
        for (AttributeDefinition attribute : this.descriptor.getAttributeTranslations().keySet()) {
            builder.addParameter(attribute);
        }
        registration.registerOperationHandler(builder.build(), this.descriptor.getAddOperationTransformation().apply(this));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy