private void parseChannel(
      XMLExtendedStreamReader reader,
      PathAddress subsystemAddress,
      Map<PathAddress, ModelNode> operations)
      throws XMLStreamException {
    String name = require(reader, XMLAttribute.NAME);
    PathAddress address = subsystemAddress.append(ChannelResourceDefinition.pathElement(name));
    ModelNode operation = Util.createAddOperation(address);
    operations.put(address, operation);

    for (int i = 0; i < reader.getAttributeCount(); i++) {
      ParseUtils.requireNoNamespaceAttribute(reader, i);
      XMLAttribute attribute = XMLAttribute.forName(reader.getAttributeLocalName(i));
      switch (attribute) {
        case NAME:
          {
            // Already parsed
            break;
          }
        case STACK:
          {
            readAttribute(reader, i, operation, ChannelResourceDefinition.Attribute.STACK);
            break;
          }
        case MODULE:
          {
            readAttribute(reader, i, operation, ChannelResourceDefinition.Attribute.MODULE);
            break;
          }
        default:
          {
            throw ParseUtils.unexpectedAttribute(reader, i);
          }
      }
    }

    while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
      XMLElement element = XMLElement.forName(reader.getLocalName());
      switch (element) {
        case FORK:
          {
            this.parseFork(reader, address, operations);
            break;
          }
        default:
          {
            throw ParseUtils.unexpectedElement(reader);
          }
      }
    }
  }
  static TransformationDescription buildTransformers(ModelVersion version) {
    ResourceTransformationDescriptionBuilder builder =
        TransformationDescriptionBuilder.Factory.createSubsystemInstance();

    if (JGroupsModel.VERSION_3_0_0.requiresTransformation(version)) {
      builder
          .getAttributeBuilder()
          .setDiscard(DiscardAttributeChecker.UNDEFINED, Attribute.DEFAULT_CHANNEL.getDefinition())
          .addRejectCheck(RejectAttributeChecker.DEFINED, Attribute.DEFAULT_CHANNEL.getDefinition())
          .addRejectCheck(RejectAttributeChecker.UNDEFINED, Attribute.DEFAULT_STACK.getDefinition())
          .end();

      builder.rejectChildResource(ChannelResourceDefinition.WILDCARD_PATH);
    } else {
      ChannelResourceDefinition.buildTransformation(version, builder);
    }

    StackResourceDefinition.buildTransformation(version, builder);

    return builder.build();
  }
  private void parseRemoteSite(
      XMLExtendedStreamReader reader,
      PathAddress relayAddress,
      Map<PathAddress, ModelNode> operations)
      throws XMLStreamException {
    String site = require(reader, XMLAttribute.NAME);
    PathAddress address = relayAddress.append(RemoteSiteResourceDefinition.pathElement(site));
    ModelNode operation = Util.createAddOperation(address);
    operations.put(address, operation);

    String cluster = null;

    for (int i = 0; i < reader.getAttributeCount(); i++) {
      String value = reader.getAttributeValue(i);
      XMLAttribute attribute = XMLAttribute.forName(reader.getAttributeLocalName(i));
      switch (attribute) {
        case NAME:
          {
            // Already parsed
            break;
          }
        case STACK:
          {
            if (this.schema.since(JGroupsSchema.VERSION_3_0)) {
              throw ParseUtils.unexpectedAttribute(reader, i);
            }
            readAttribute(
                reader, i, operation, RemoteSiteResourceDefinition.DeprecatedAttribute.STACK);
            break;
          }
        case CLUSTER:
          {
            if (this.schema.since(JGroupsSchema.VERSION_3_0)) {
              throw ParseUtils.unexpectedAttribute(reader, i);
            }
            cluster = value;
            break;
          }
        case CHANNEL:
          {
            if (this.schema.since(JGroupsSchema.VERSION_3_0)) {
              readAttribute(reader, i, operation, RemoteSiteResourceDefinition.Attribute.CHANNEL);

              // We need to populate the deprecated STACK attribute so that we have enough context
              // for transforming the add operation
              PathAddress subsystemAddress =
                  PathAddress.pathAddress(JGroupsSubsystemResourceDefinition.PATH);
              PathAddress channelAddress =
                  subsystemAddress.append(ChannelResourceDefinition.pathElement(value));
              ModelNode channelOperation = operations.get(channelAddress);
              if (channelOperation != null) {
                String stack;
                if (channelOperation.hasDefined(
                    ChannelResourceDefinition.Attribute.STACK.getDefinition().getName())) {
                  stack =
                      channelOperation
                          .get(ChannelResourceDefinition.Attribute.STACK.getDefinition().getName())
                          .asString();
                } else {
                  stack =
                      operations
                          .get(subsystemAddress)
                          .get(
                              JGroupsSubsystemResourceDefinition.Attribute.DEFAULT_STACK
                                  .getDefinition()
                                  .getName())
                          .asString();
                }
                setAttribute(
                    reader,
                    stack,
                    operation,
                    RemoteSiteResourceDefinition.DeprecatedAttribute.STACK);
              }
              break;
            }
          }
        default:
          {
            throw ParseUtils.unexpectedAttribute(reader, i);
          }
      }
    }

    if (this.schema.since(JGroupsSchema.VERSION_3_0)) {
      if (!operation.hasDefined(
          RemoteSiteResourceDefinition.Attribute.CHANNEL.getDefinition().getName())) {
        throw ParseUtils.missingRequired(reader, EnumSet.of(XMLAttribute.CHANNEL));
      }
    } else {
      if (!operation.hasDefined(
          RemoteSiteResourceDefinition.DeprecatedAttribute.STACK.getDefinition().getName())) {
        throw ParseUtils.missingRequired(reader, EnumSet.of(XMLAttribute.STACK));
      }
      String channel = (cluster != null) ? cluster : site;
      setAttribute(reader, channel, operation, RemoteSiteResourceDefinition.Attribute.CHANNEL);

      // We need to create a corresponding channel add operation
      PathAddress subsystemAddress =
          PathAddress.pathAddress(JGroupsSubsystemResourceDefinition.PATH);
      PathAddress channelAddress =
          subsystemAddress.append(ChannelResourceDefinition.pathElement(channel));
      ModelNode channelOperation = Util.createAddOperation(channelAddress);
      String stack =
          operation
              .get(RemoteSiteResourceDefinition.DeprecatedAttribute.STACK.getDefinition().getName())
              .asString();
      setAttribute(reader, stack, channelOperation, ChannelResourceDefinition.Attribute.STACK);
      operations.put(channelAddress, channelOperation);
    }

    ParseUtils.requireNoContent(reader);
  }