@Override
  public void execute(OperationContext context, ModelNode operation)
      throws OperationFailedException {
    ModelNode operationModel = new ModelNode();
    populateModel(operation, operationModel);
    String attributeName = NAME.resolveModelAttribute(context, operationModel).asString();
    final ImmutableManagementResourceRegistration registry = context.getResourceRegistration();
    final boolean useEnhancedSyntax = containsEnhancedSyntax(attributeName, registry);
    String attributeExpression = attributeName;
    if (useEnhancedSyntax) {
      attributeName = extractAttributeName(attributeName);
    }
    final AttributeAccess attributeAccess =
        context
            .getResourceRegistration()
            .getAttributeAccess(PathAddress.EMPTY_ADDRESS, attributeName);
    if (attributeAccess == null) {
      throw new OperationFailedException(
          ControllerLogger.ROOT_LOGGER.unknownAttribute(attributeName));
    }
    final PathAddress address = PathAddress.pathAddress(operation.get(OP_ADDR));

    final ModelNode readResponse = new ModelNode();

    // prepare write operation
    ModelNode writeOperation = Util.createOperation(WriteAttributeHandler.DEFINITION, address);
    writeOperation.get(NAME.getName()).set(useEnhancedSyntax ? attributeExpression : attributeName);
    ModelNode writeOperationValue =
        writeOperation.get(
            ModelDescriptionConstants.VALUE); // value will be set in modification step

    if (attributeAccess.getStorageType() == AttributeAccess.Storage.CONFIGURATION) {

      // Steps need to be performed before any other steps, so they are added in opposite order
      // with addFirst=true parameter.

      // 2. modify value and register writing step
      context.addStep(
          (context1, operation1) -> {
            updateModel(
                context,
                operationModel,
                attributeAccess.getAttributeDefinition(),
                readResponse.get(RESULT));

            // add write step
            if (requiredReadWriteAccess) {
              writeOperationValue.set(readResponse.get(RESULT));
              context.addStep(
                  writeOperation,
                  WriteAttributeHandler.INSTANCE,
                  OperationContext.Stage.MODEL,
                  true);
            }
          },
          OperationContext.Stage.MODEL,
          true);

      // 1. read current attribute value
      ModelNode readAttributeOperation =
          Util.getReadAttributeOperation(
              address, useEnhancedSyntax ? attributeExpression : attributeName);
      context.addStep(
          readResponse,
          readAttributeOperation,
          ReadAttributeHandler.INSTANCE,
          OperationContext.Stage.MODEL,
          true);
    } else {
      assert attributeAccess.getStorageType() == AttributeAccess.Storage.RUNTIME;

      // For Storage.RUNTIME attributes, attributes need to be registered with reader and writer
      // step handlers,
      // which must postpone reading / writing to RUNTIME stage (by registering new RUNTIME steps
      // which will
      // perform actual reading / writing).

      // Steps need to be performed before any other steps, so they are added in opposite order
      // with addFirst=true parameter.

      // 3. write modified value
      if (requiredReadWriteAccess) {
        context.addStep(
            readResponse,
            writeOperation,
            WriteAttributeHandler.INSTANCE,
            OperationContext.Stage.MODEL,
            true);
      }

      // 2. modify value
      context.addStep(
          (context1, operation1) -> {
            context.addStep(
                (context2, operation2) -> {
                  updateModel(
                      context2,
                      operationModel,
                      attributeAccess.getAttributeDefinition(),
                      readResponse.get(RESULT));
                  writeOperationValue.set(readResponse.get(RESULT));
                },
                OperationContext.Stage.RUNTIME);
          },
          OperationContext.Stage.MODEL,
          true);

      // 1. read current attribute value
      ModelNode readAttributeOperation =
          Util.getReadAttributeOperation(
              address, useEnhancedSyntax ? attributeExpression : attributeName);
      context.addStep(
          readResponse,
          readAttributeOperation,
          ReadAttributeHandler.INSTANCE,
          OperationContext.Stage.MODEL,
          true);
    }
  }
  @Override
  public void execute(OperationContext context, ModelNode operation)
      throws OperationFailedException {
    NAME.validateOperation(operation);
    final ModelNode nameModel =
        GlobalOperationAttributes.NAME.resolveModelAttribute(context, operation);
    final PathAddress address = context.getCurrentAddress();
    final ImmutableManagementResourceRegistration registry = context.getResourceRegistration();
    if (registry == null) {
      throw new OperationFailedException(ControllerLogger.ROOT_LOGGER.noSuchResourceType(address));
    }
    final boolean useEnhancedSyntax = containsEnhancedSyntax(nameModel.asString(), registry);
    final String attributeName;
    final String attributeExpression;
    if (useEnhancedSyntax) {
      attributeExpression = nameModel.asString();
      attributeName = extractAttributeName(nameModel.asString());
    } else {
      attributeName = nameModel.asString();
      attributeExpression = attributeName;
    }

    final AttributeAccess attributeAccess =
        registry.getAttributeAccess(PathAddress.EMPTY_ADDRESS, attributeName);
    if (attributeAccess == null) {
      throw new OperationFailedException(
          ControllerLogger.ROOT_LOGGER.unknownAttribute(attributeName));
    } else if (attributeAccess.getAccessType() != AttributeAccess.AccessType.READ_WRITE) {
      throw new OperationFailedException(
          ControllerLogger.ROOT_LOGGER.attributeNotWritable(attributeName));
    } else {

      // Authorize
      ModelNode currentValue;
      if (attributeAccess.getStorageType() == AttributeAccess.Storage.CONFIGURATION) {
        ModelNode model = context.readResourceForUpdate(PathAddress.EMPTY_ADDRESS).getModel();
        currentValue = model.has(attributeName) ? model.get(attributeName) : new ModelNode();
      } else {
        currentValue = new ModelNode();
      }
      AuthorizationResult authorizationResult =
          context.authorize(operation, attributeName, currentValue);
      if (authorizationResult.getDecision() == AuthorizationResult.Decision.DENY) {
        throw ControllerLogger.ROOT_LOGGER.unauthorized(
            operation.require(OP).asString(), address, authorizationResult.getExplanation());
      }

      if (attributeAccess.getStorageType() == AttributeAccess.Storage.CONFIGURATION
          && !registry.isRuntimeOnly()) {
        // if the attribute is stored in the configuration, we can read its
        // old and new value from the resource's model before and after executing its write handler
        final ModelNode oldValue = currentValue.clone();
        doExecuteInternal(
            context,
            operation,
            attributeAccess,
            attributeName,
            currentValue,
            useEnhancedSyntax,
            attributeExpression);
        ModelNode model = context.readResource(PathAddress.EMPTY_ADDRESS).getModel();
        ModelNode newValue = model.has(attributeName) ? model.get(attributeName) : new ModelNode();
        emitAttributeValueWrittenNotification(context, address, attributeName, oldValue, newValue);

      } else {
        assert attributeAccess.getStorageType() == AttributeAccess.Storage.RUNTIME;

        // if the attribute is a runtime attribute, its old and new values must
        // be read using the attribute's read handler and the write operation
        // must be sandwiched between the 2 calls to the read handler.
        // Each call to the read handlers will have their own results while
        // the call to the write handler will use this OSH context result.

        OperationContext.Stage currentStage = context.getCurrentStage();

        final ModelNode readAttributeOperation =
            Util.createOperation(READ_ATTRIBUTE_OPERATION, address);
        readAttributeOperation.get(NAME.getName()).set(attributeName);
        ReadAttributeHandler readAttributeHandler = new ReadAttributeHandler(null, null, false);

        // create 2 model nodes to store the result of the read-attribute operations
        // before and after writing the value
        final ModelNode oldValue = new ModelNode();
        final ModelNode newValue = new ModelNode();

        // We're going to add a bunch of steps, but we want them to execute right away
        // so we use the 'addFirst=true' param to addStep. That means we add them
        // in reverse order of how they will execute

        // 4th OSH is to emit the notification
        context.addStep(
            new OperationStepHandler() {
              @Override
              public void execute(OperationContext context, ModelNode operation)
                  throws OperationFailedException {
                // aggregate data from the 2 read-attribute operations
                emitAttributeValueWrittenNotification(
                    context, address, attributeName, oldValue.get(RESULT), newValue.get(RESULT));
              }
            },
            currentStage,
            true);

        // 3rd OSH is to read the new value
        context.addStep(newValue, readAttributeOperation, readAttributeHandler, currentStage, true);

        // 2nd OSH is to write the value
        context.addStep(
            new OperationStepHandler() {
              @Override
              public void execute(OperationContext context, ModelNode operation)
                  throws OperationFailedException {
                doExecuteInternal(
                    context,
                    operation,
                    attributeAccess,
                    attributeName,
                    oldValue.get(RESULT),
                    useEnhancedSyntax,
                    attributeExpression);
              }
            },
            currentStage,
            true);

        // 1st OSH is to read the old value
        context.addStep(oldValue, readAttributeOperation, readAttributeHandler, currentStage, true);
      }
    }
  }