gt:                     if (this.schema.since(JGroupsSchema.VERSION_3_0)) {
context: /*
   * JBoss, Home of Professional Open Source.
   * Copyright 2014, Red Hat, Inc., and individual contributors
   * as indicated by the @author tags. See the copyright.txt file in the
   * distribution for a full listing of individual contributors.
   *
   * This is free software; you can redistribute it and/or modify it
   * under the terms of the GNU Lesser General Public License as
   * published by the Free Software Foundation; either version 2.1 of
   * the License, or (at your option) any later version.
   *
   * This software is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this software; if not, write to the Free
   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   */
  package org.jboss.as.clustering.jgroups.subsystem;
  
  import java.util.Collections;
  import java.util.EnumSet;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import javax.xml.stream.XMLStreamConstants;
  import javax.xml.stream.XMLStreamException;
  
  import org.jboss.as.clustering.controller.Attribute;
  import org.jboss.as.controller.AttributeDefinition;
  import org.jboss.as.controller.AttributeParser;
  import org.jboss.as.controller.PathAddress;
  import org.jboss.as.controller.operations.common.Util;
  import org.jboss.as.controller.parsing.ParseUtils;
  import org.jboss.dmr.ModelNode;
  import org.jboss.staxmapper.XMLElementReader;
  import org.jboss.staxmapper.XMLExtendedStreamReader;
  
  /**
   * XML reader for the JGroups subsystem.
   * @author Paul Ferraro
   */
  @SuppressWarnings({ "deprecation", "static-method" })
  public class JGroupsSubsystemXMLReader implements XMLElementReader<List<ModelNode>> {
      private final JGroupsSchema schema;
  
      JGroupsSubsystemXMLReader(JGroupsSchema schema) {
          this.schema = schema;
      }
  
      @Override
      public void readElement(XMLExtendedStreamReader reader, List<ModelNode> result) throws XMLStreamException {
  
          Map<PathAddress, ModelNode> operations = new LinkedHashMap<>();
  
          PathAddress address = PathAddress.pathAddress(JGroupsSubsystemResourceDefinition.PATH);
          ModelNode operation = Util.createAddOperation(address);
          operations.put(address, operation);
  
          if (!this.schema.since(JGroupsSchema.VERSION_3_0)) {
              String defaultStack = require(reader, XMLAttribute.DEFAULT_STACK);
              setAttribute(reader, defaultStack, operation, JGroupsSubsystemResourceDefinition.Attribute.DEFAULT_STACK);
          }
  
          while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
              XMLElement element = XMLElement.forName(reader.getLocalName());
              switch (element) {
                  case CHANNELS: {
                      if (this.schema.since(JGroupsSchema.VERSION_3_0)) {
                          this.parseChannels(reader, address, operations);
                          break;
                      }
                  }
                  case STACKS: {
                      if (this.schema.since(JGroupsSchema.VERSION_3_0)) {
                          this.parseStacks(reader, address, operations);
                          break;
                      }
                  }
                  case STACK: {
                      if (!this.schema.since(JGroupsSchema.VERSION_3_0)) {
                          this.parseStack(reader, address, operations);
                          break;
                      }
                  }
                  default: {
                      throw ParseUtils.unexpectedElement(reader);
                  }
              }
          }
  
          // Version prior to 4_0 schema did not require stack being defined,
          // thus iterate over channel add operations and set the stack explicitly.
          if (!this.schema.since(JGroupsSchema.VERSION_4_0)) {
              ModelNode defaultStack = operation.get(JGroupsSubsystemResourceDefinition.Attribute.DEFAULT_STACK.getName());
  
              for (Map.Entry<PathAddress, ModelNode> entry : operations.entrySet()) {
                  PathAddress opAddr = entry.getKey();
                  if (opAddr.getLastElement().getKey().equals(ChannelResourceDefinition.WILDCARD_PATH.getKey())) {
                      ModelNode op = entry.getValue();
                      if (!op.hasDefined(ChannelResourceDefinition.Attribute.STACK.getName())) {
                          op.get(ChannelResourceDefinition.Attribute.STACK.getName()).set(defaultStack);
                      }
                  }
              }
          }
  
          result.addAll(operations.values());
      }
  
      private void parseChannels(XMLExtendedStreamReader reader, PathAddress address, Map<PathAddress, ModelNode> operations) throws XMLStreamException {
  
          ModelNode operation = operations.get(address);
  
          for (int i = 0; i < reader.getAttributeCount(); i++) {
              ParseUtils.requireNoNamespaceAttribute(reader, i);
              XMLAttribute attribute = XMLAttribute.forName(reader.getAttributeLocalName(i));
              switch (attribute) {
                  case DEFAULT: {
                      readAttribute(reader, i, operation, JGroupsSubsystemResourceDefinition.Attribute.DEFAULT_CHANNEL);
                      break;
                  }
                  default: {
                      throw ParseUtils.unexpectedAttribute(reader, i);
                  }
              }
          }
  
          while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
              XMLElement element = XMLElement.forName(reader.getLocalName());
              switch (element) {
                  case CHANNEL: {
                      this.parseChannel(reader, address, operations);
                      break;
                  }
                  default: {
                      throw ParseUtils.unexpectedElement(reader);
                  }
              }
          }
      }
  
      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;
                  }
                  case CLUSTER: {
                      if (this.schema.since(JGroupsSchema.VERSION_4_0)) {
                          readAttribute(reader, i, operation, ChannelResourceDefinition.Attribute.CLUSTER);
                          break;
                      }
                  }
                  case STATISTICS_ENABLED: {
                      if (this.schema.since(JGroupsSchema.VERSION_5_0)) {
                          readAttribute(reader, i, operation, ChannelResourceDefinition.Attribute.STATISTICS_ENABLED);
                          break;
                      }
                  }
                  default: {
                      throw ParseUtils.unexpectedAttribute(reader, i);
                  }
              }
          }
  
          if (this.schema.since(JGroupsSchema.VERSION_4_0)) {
              require(reader, operation, ChannelResourceDefinition.Attribute.STACK);
          }
  
          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);
                  }
              }
          }
      }
  
      private void parseFork(XMLExtendedStreamReader reader, PathAddress channelAddress, Map<PathAddress, ModelNode> operations) throws XMLStreamException {
          String name = require(reader, XMLAttribute.NAME);
          PathAddress address = channelAddress.append(ForkResourceDefinition.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;
                  }
                  default: {
                      throw ParseUtils.unexpectedAttribute(reader, i);
                  }
              }
          }
  
          while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
              XMLElement element = XMLElement.forName(reader.getLocalName());
              switch (element) {
                  case PROTOCOL: {
                      this.parseProtocol(reader, address, operations);
                      break;
                  }
                  default: {
                      throw ParseUtils.unexpectedElement(reader);
                  }
              }
          }
      }
  
      private void parseStacks(XMLExtendedStreamReader reader, PathAddress address, Map<PathAddress, ModelNode> operations) throws XMLStreamException {
  
          ModelNode operation = operations.get(address);
  
          for (int i = 0; i < reader.getAttributeCount(); i++) {
              ParseUtils.requireNoNamespaceAttribute(reader, i);
              XMLAttribute attribute = XMLAttribute.forName(reader.getAttributeLocalName(i));
              switch (attribute) {
                  case DEFAULT: {
                      readAttribute(reader, i, operation, JGroupsSubsystemResourceDefinition.Attribute.DEFAULT_STACK);
                      break;
                  }
                  default: {
                      throw ParseUtils.unexpectedAttribute(reader, i);
                  }
              }
          }
  
          while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
              XMLElement element = XMLElement.forName(reader.getLocalName());
              switch (element) {
                  case STACK: {
                      this.parseStack(reader, address, operations);
                      break;
                  }
                  default: {
                      throw ParseUtils.unexpectedElement(reader);
                  }
              }
          }
      }
  
      private void parseStack(XMLExtendedStreamReader reader, PathAddress subsystemAddress, Map<PathAddress, ModelNode> operations) throws XMLStreamException {
          String name = require(reader, XMLAttribute.NAME);
          PathAddress address = subsystemAddress.append(StackResourceDefinition.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 STATISTICS_ENABLED: {
                      if (this.schema.since(JGroupsSchema.VERSION_5_0)) {
                          readAttribute(reader, i, operation, StackResourceDefinition.Attribute.STATISTICS_ENABLED);
                          break;
                      }
                  }
                  default: {
                      throw ParseUtils.unexpectedAttribute(reader, i);
                  }
              }
          }
  
          while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
              XMLElement element = XMLElement.forName(reader.getLocalName());
              switch (element) {
                  case TRANSPORT: {
                      this.parseTransport(reader, address, operations);
                      break;
                  }
                  case PROTOCOL: {
                      this.parseProtocol(reader, address, operations);
                      break;
                  }
                  case RELAY: {
                      if (this.schema.since(JGroupsSchema.VERSION_2_0)) {
                          this.parseRelay(reader, address, operations);
                          break;
                      }
                  }
                  case SOCKET_PROTOCOL: {
                      if (this.schema.since(JGroupsSchema.VERSION_5_0)) {
                          this.parseSocketProtocol(reader, address, operations);
                          break;
                      }
                  }
                  case SOCKET_DISCOVERY_PROTOCOL: {
                      if (this.schema.since(JGroupsSchema.VERSION_5_0)) {
                          this.parseSocketDiscoveryProtocol(reader, address, operations);
                          break;
                      }
                  }
                  case JDBC_PROTOCOL: {
                      if (this.schema.since(JGroupsSchema.VERSION_5_0)) {
                          this.parseJDBCProtocol(reader, address, operations);
                          break;
                      }
                  }
                  case ENCRYPT_PROTOCOL: {
                      if (this.schema.since(JGroupsSchema.VERSION_5_0)) {
                          this.parseEncryptProtocol(reader, address, operations);
                          break;
                      }
                  }
                  case AUTH_PROTOCOL: {
                      if (this.schema.since(JGroupsSchema.VERSION_5_0)) {
                          this.parseAuthProtocol(reader, address, operations);
                          break;
                      }
                  }
                  default: {
                      throw ParseUtils.unexpectedElement(reader);
                  }
              }
          }
      }
  
      private void parseTransport(XMLExtendedStreamReader reader, PathAddress stackAddress, Map<PathAddress, ModelNode> operations) throws XMLStreamException {
  
          String type = require(reader, XMLAttribute.TYPE);
          PathAddress address = stackAddress.append(TransportResourceDefinition.pathElement(type));
          ModelNode operation = Util.createAddOperation(address);
          operations.put(address, operation);
  
          for (int i = 0; i < reader.getAttributeCount(); i++) {
              XMLAttribute attribute = XMLAttribute.forName(reader.getAttributeLocalName(i));
              switch (attribute) {
                  case SHARED: {
                      readAttribute(reader, i, operation, TransportResourceDefinition.Attribute.SHARED);
                      break;
                  }
                  case SOCKET_BINDING: {
                      readAttribute(reader, i, operation, TransportResourceDefinition.Attribute.SOCKET_BINDING);
                      break;
                  }
                  case DIAGNOSTICS_SOCKET_BINDING: {
                      readAttribute(reader, i, operation, TransportResourceDefinition.Attribute.DIAGNOSTICS_SOCKET_BINDING);
                      break;
                  }
                  case DEFAULT_EXECUTOR: {
                      readAttribute(reader, i, operation, TransportResourceDefinition.ThreadingAttribute.DEFAULT_EXECUTOR);
                      break;
                  }
                  case OOB_EXECUTOR: {
                      readAttribute(reader, i, operation, TransportResourceDefinition.ThreadingAttribute.OOB_EXECUTOR);
                      break;
                  }
                  case TIMER_EXECUTOR: {
                      readAttribute(reader, i, operation, TransportResourceDefinition.ThreadingAttribute.TIMER_EXECUTOR);
                      break;
                  }
                  case THREAD_FACTORY: {
                      readAttribute(reader, i, operation, TransportResourceDefinition.ThreadingAttribute.THREAD_FACTORY);
                      break;
                  }
                  case SITE: {
                      if (this.schema.since(JGroupsSchema.VERSION_1_1)) {
                          readAttribute(reader, i, operation, TransportResourceDefinition.Attribute.SITE);
                          break;
                      }
                  }
                  case RACK: {
                      if (this.schema.since(JGroupsSchema.VERSION_1_1)) {
                          readAttribute(reader, i, operation, TransportResourceDefinition.Attribute.RACK);
                          break;
                      }
                  }
                  case MACHINE: {
                      if (this.schema.since(JGroupsSchema.VERSION_1_1)) {
                          readAttribute(reader, i, operation, TransportResourceDefinition.Attribute.MACHINE);
                          break;
                      }
                  }
                  case CLIENT_SOCKET_BINDING: {
                      if (this.schema.since(JGroupsSchema.VERSION_7_0)) {
                          readAttribute(reader, i, operation, SocketTransportResourceDefinition.Attribute.CLIENT_SOCKET_BINDING);
                          break;
                      }
                  }
                  default: {
                      this.parseProtocolAttribute(reader, i, operation);
                  }
              }
          }
  
          while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
              XMLElement element = XMLElement.forName(reader.getLocalName());
              switch (element) {
                  case DEFAULT_THREAD_POOL: {
                      if (this.schema.since(JGroupsSchema.VERSION_3_0)) {
                          this.parseThreadPool(ThreadPoolResourceDefinition.DEFAULT, reader, address, operations);
                          break;
                      }
                  }
                  case INTERNAL_THREAD_POOL: {
                      if (this.schema.since(JGroupsSchema.VERSION_6_0)) {
                          throw ParseUtils.unexpectedElement(reader);
                      }
                      if (this.schema.since(JGroupsSchema.VERSION_3_0)) {
                          this.parseThreadPool(ThreadPoolResourceDefinition.INTERNAL, reader, address, operations);
                          break;
                      }
                  }
                  case OOB_THREAD_POOL: {
                      if (this.schema.since(JGroupsSchema.VERSION_6_0)) {
                          throw ParseUtils.unexpectedElement(reader);
                      }
  