Package org.jboss.as.model

Source Code of org.jboss.as.model.ModelXmlParsers

/*
* JBoss, Home of Professional Open Source.
* Copyright 2010, 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.model;

import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
import static org.jboss.as.model.ParseUtils.invalidAttributeValue;
import static org.jboss.as.model.ParseUtils.readNamespaces;
import static org.jboss.as.model.ParseUtils.readSchemaLocations;
import static org.jboss.as.model.ParseUtils.readStringAttributeElement;
import static org.jboss.as.model.ParseUtils.requireNoAttributes;
import static org.jboss.as.model.ParseUtils.requireNoContent;
import static org.jboss.as.model.ParseUtils.requireSingleAttribute;
import static org.jboss.as.model.ParseUtils.unexpectedAttribute;
import static org.jboss.as.model.ParseUtils.unexpectedElement;
import static org.jboss.as.model.ParseUtils.unexpectedEndElement;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;

import org.jboss.as.Extension;
import org.jboss.as.ExtensionContext;
import org.jboss.as.model.socket.AbstractInterfaceCriteriaElement;
import org.jboss.as.model.socket.CompoundCriteriaElement;
import org.jboss.as.model.socket.InterfaceAdd;
import org.jboss.as.model.socket.InterfaceParsingUtils;
import org.jboss.as.model.socket.SocketBindingAdd;
import org.jboss.as.model.socket.SocketBindingGroupUpdate;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoadException;
import org.jboss.staxmapper.XMLElementReader;
import org.jboss.staxmapper.XMLExtendedStreamReader;
import org.jboss.staxmapper.XMLMapper;

/**
* A set of parsers for the JBoss Application Server XML schema, which result in lists of updates to apply to new models.
*
* @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
*/
public final class ModelXmlParsers {

    private ModelXmlParsers() {
    }

    public static void registerAll(final XMLMapper xmlMapper) {
        xmlMapper.registerRootElement(new QName(Namespace.DOMAIN_1_0.getUriString(), Element.DOMAIN.getLocalName()), DOMAIN_XML_READER);
        xmlMapper.registerRootElement(new QName(Namespace.DOMAIN_1_0.getUriString(), Element.HOST.getLocalName()), HOST_XML_READER);
        xmlMapper.registerRootElement(new QName(Namespace.DOMAIN_1_0.getUriString(), Element.SERVER.getLocalName()), SERVER_XML_READER);
    }

    /**
     * The XML reader for the {@code &lt;domain&gt;} root element.
     */
    public static final XMLElementReader<List<? super AbstractDomainModelUpdate<?>>> DOMAIN_XML_READER = new XMLElementReader<List<? super AbstractDomainModelUpdate<?>>>() {
        public void readElement(final XMLExtendedStreamReader reader, final List<? super AbstractDomainModelUpdate<?>> objects) throws XMLStreamException {
            parseDomainRootElement(reader, objects);
        }
    };

    /**
     * The XML reader for the {@code &lt;host&gt;} root element.
     */
    public static final XMLElementReader<List<? super AbstractHostModelUpdate<?>>> HOST_XML_READER = new XMLElementReader<List<? super AbstractHostModelUpdate<?>>>() {
        public void readElement(final XMLExtendedStreamReader reader, final List<? super AbstractHostModelUpdate<?>> objects) throws XMLStreamException {
            parseHostRootElement(reader, objects);
        }
    };

    /**
     * The XML reader for the {@code &lt;server&gt;} root element.
     */
    public static final XMLElementReader<List<? super AbstractServerModelUpdate<?>>> SERVER_XML_READER = new XMLElementReader<List<? super AbstractServerModelUpdate<?>>>() {
        public void readElement(final XMLExtendedStreamReader reader, final List<? super AbstractServerModelUpdate<?>> objects) throws XMLStreamException {
            parseServerRootElement(reader, objects);
        }
    };

    public static void parseServerRootElement(final XMLExtendedStreamReader reader, final List<? super AbstractServerModelUpdate<?>> list) throws XMLStreamException {
        final List<NamespacePrefix> prefixes = readNamespaces(reader);
        if (! prefixes.isEmpty()) list.add(new ServerNamespaceUpdate(prefixes));

        // Read attributes
        String serverName = null;
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            switch (Namespace.forUri(reader.getAttributeNamespace(i))) {
                case DOMAIN_1_0: {
                    final String value = reader.getAttributeValue(i);
                    final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                    switch (attribute) {
                        case NAME: {
                            if (serverName != null)
                                throw unexpectedAttribute(reader, i);
                            serverName = value;
                            break;
                        }
                        default: throw unexpectedAttribute(reader, i);
                    }
                    break;
                }
                case XML_SCHEMA_INSTANCE: {
                    switch (Attribute.forName(reader.getAttributeLocalName(i))) {
                        case SCHEMA_LOCATION: {
                            final List<SchemaLocation> locationList = readSchemaLocations(reader, i);
                            list.add(new ServerSchemaLocationUpdate(locationList));
                            break;
                        }
                        case NO_NAMESPACE_SCHEMA_LOCATION: {
                            // todo, jeez
                            break;
                        }
                        default: {
                            throw unexpectedAttribute(reader, i);
                        }
                    }
                    break;
                }
                case UNKNOWN: {
                    if (reader.getAttributeNamespace(i) != null)
                        throw unexpectedAttribute(reader, i);
                    final String value = reader.getAttributeValue(i);
                    final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                    switch (attribute) {
                        case NAME: {
                            if (serverName != null)
                                throw unexpectedAttribute(reader, i);
                            serverName = value;
                            break;
                        }
                        default: throw unexpectedAttribute(reader, i);
                    }
                    break;
                }
            }
        }

        if (serverName != null && serverName.length() != 0) {
            list.add(new ServerNameUpdate(serverName));
        }

        // Content
        // Handle elements : sequence

        Element element = nextElement(reader);
        if (element == Element.EXTENSIONS) {
            Set<String> extensionModules = parseExtensions(reader);
            for (String moduleName : extensionModules) {
                list.add(new ServerExtensionAdd(moduleName));
            }
            element = nextElement(reader);
        }
        if (element == Element.PATHS) {
            parseServerModelPaths(reader, list);
            element = nextElement(reader);
        }
        if (element == Element.MANAGEMENT) {
            parseServerManagement(reader, list);
            element = nextElement(reader);
        }
        // Single profile
        if (element == Element.PROFILE) {
            parseServerProfile(reader, list);
            element = nextElement(reader);
        }
        // Interfaces
        Set<String> interfaceNames = null;
        if (element == Element.INTERFACES) {
            interfaceNames = parseServerModelInterfaces(reader, list);
            element = nextElement(reader);
        }
        // Single socket binding group
        if (element == Element.SOCKET_BINDING_GROUP) {
            final List<SocketBindingAdd> bindingUpdates = new ArrayList<SocketBindingAdd>();
            final SocketBindingGroupUpdate group = parseSocketBindingGroup(reader, bindingUpdates, interfaceNames, false);
            // Build updates
            list.add(new ServerSocketBindingGroupUpdate(group));
            for(final SocketBindingAdd bindingUpdate : bindingUpdates) {
                list.add(new ServerSocketBindingUpdate(bindingUpdate));
            }
            element = nextElement(reader);
        }
        // System properties
        if (element == Element.SYSTEM_PROPERTIES) {
            parseServerModelSystemProperties(reader, list);
            element = nextElement(reader);
        }
        if (element == Element.DEPLOYMENT_REPOSITORY) {
            // Handle attributes
            boolean enabled = true;
            int interval = 0;
            String path = null;
            String name= null;
            String relativeTo = null;
            final int attrCount = reader.getAttributeCount();
            for (int i = 0; i < attrCount; i ++) {
                final String value = reader.getAttributeValue(i);
                if (reader.getAttributeNamespace(i) != null) {
                    throw ParseUtils.unexpectedAttribute(reader, i);
                } else {
                    final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                    switch (attribute) {
                        case PATH: {
                            path = value;
                            break;
                        }
                        case NAME: {
                            name = value;
                            break;
                        }
                        case RELATIVE_TO: {
                            relativeTo = value;
                            break;
                        }
                        case SCAN_INTERVAL: {
                            interval = Integer.parseInt(value);
                            break;
                        }
                        case SCAN_ENABLED: {
                            enabled = Boolean.parseBoolean(value);
                            break;
                        }
                        default:
                            throw ParseUtils.unexpectedAttribute(reader, i);
                    }
                }
            }
            if(path == null) {
                ParseUtils.missingRequired(reader, Collections.singleton("path"));
            }
            requireNoContent(reader);
            final ServerDeploymentRepositoryAdd action = new ServerDeploymentRepositoryAdd(path, interval, enabled);
            action.setName(name);
            action.setRelativeTo(relativeTo);
            list.add(action);
            element = nextElement(reader);
        }
        if (element == Element.DEPLOYMENTS) {
            parseServerDeployments(reader, list);
            element = nextElement(reader);
        }
        if (element != null) {
            throw unexpectedElement(reader);
        }
    }

    public static void parseHostRootElement(final XMLExtendedStreamReader reader, final List<? super AbstractHostModelUpdate<?>> list) throws XMLStreamException {
        final List<NamespacePrefix> prefixes = readNamespaces(reader);
        if (! prefixes.isEmpty()) list.add(new HostNamespaceUpdate(prefixes));

        // Read attributes
        String name = null;
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            switch (Namespace.forUri(reader.getAttributeNamespace(i))) {
                case DOMAIN_1_0: {
                    final String value = reader.getAttributeValue(i);
                    final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                    switch (attribute) {
                        case NAME: {
                            if (name != null)
                                throw unexpectedAttribute(reader, i);
                            name = value;
                            break;
                        }
                        default: throw unexpectedAttribute(reader, i);
                    }
                    break;
                }
                case XML_SCHEMA_INSTANCE: {
                    switch (Attribute.forName(reader.getAttributeLocalName(i))) {
                        case SCHEMA_LOCATION: {
                            final List<SchemaLocation> locationList = readSchemaLocations(reader, i);
                            list.add(new HostSchemaLocationUpdate(locationList));
                            break;
                        }
                        case NO_NAMESPACE_SCHEMA_LOCATION: {
                            // TODO, jeez
                            break;
                        }
                        default: {
                            throw unexpectedAttribute(reader, i);
                        }
                    }
                    break;
                }
                case UNKNOWN: {
                    final String value = reader.getAttributeValue(i);
                    final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                    switch (attribute) {
                        case NAME: {
                            if (name != null)
                                throw unexpectedAttribute(reader, i);
                            name = value;
                            break;
                        }
                        default: throw unexpectedAttribute(reader, i);
                    }
                    break;
                }
            }
        }

        if (name != null && name.length() != 0) {
            list.add(new HostNameUpdate(name));
        }

        // Content
        // Handle elements: sequence

        Element element = nextElement(reader);

        if (element == Element.EXTENSIONS) {
            Set<String> extensionModules = parseExtensions(reader);
            for (String moduleName : extensionModules) {
                list.add(new HostExtensionAdd(moduleName));
            }
            element = nextElement(reader);
        }
        if (element == Element.PATHS) {
            parseHostPaths(reader, list);
            element = nextElement(reader);
        }
        if (element == Element.SYSTEM_PROPERTIES) {
            parseHostSystemProperties(reader, list);
            element = nextElement(reader);
        }
        if (element == Element.MANAGEMENT) {
            parseManagement(reader, list);
            element = nextElement(reader);
        }
        if (element == Element.DOMAIN_CONTROLLER) {
            parseDomainController(reader, list);
            element = nextElement(reader);
        }
        if (element == Element.INTERFACES) {
            parseHostInterfaces(reader, list);
            element = nextElement(reader);
        }
        if (element == Element.JVMS) {
            parseJvms(reader, list);
            element = nextElement(reader);
        }
        if (element == Element.SERVERS) {
            parseServers(reader, list);
            element = nextElement(reader);
        }
    }

    public static void parseDomainRootElement(final XMLExtendedStreamReader reader, final List<? super AbstractDomainModelUpdate<?>> list) throws XMLStreamException {

        // Read namespaces
        final List<NamespacePrefix> prefixes = readNamespaces(reader);
        if (! prefixes.isEmpty()) list.add(new DomainNamespaceUpdate(prefixes));

        // Read attributes
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            switch (Namespace.forUri(reader.getAttributeNamespace(i))) {
                case DOMAIN_1_0: {
                    throw unexpectedAttribute(reader, i);
                }
                case XML_SCHEMA_INSTANCE: {
                    switch (Attribute.forName(reader.getAttributeLocalName(i))) {
                        case SCHEMA_LOCATION: {
                            final List<SchemaLocation> locationList = readSchemaLocations(reader, i);
                            list.add(new DomainSchemaLocationUpdate(locationList));
                            break;
                        }
                        case NO_NAMESPACE_SCHEMA_LOCATION: {
                            // TODO, jeez
                            break;
                        }
                        default: {
                            throw unexpectedAttribute(reader, i);
                        }
                    }
                }
            }
        }

        // Content
        // Handle elements: sequence

        Element element = nextElement(reader);
        if (element == Element.EXTENSIONS) {
            Set<String> extensionModules = parseExtensions(reader);
            for (String moduleName : extensionModules) {
                list.add(new DomainExtensionAdd(moduleName));
            }
            element = nextElement(reader);
        }
        if (element == Element.PATHS) {
            parseDomainPaths(reader, list);
            element = nextElement(reader);
        }
        if (element == Element.PROFILES) {
            parseProfiles(reader, list);
            element = nextElement(reader);
        }
        Set<String> interfaceNames = Collections.emptySet();
        if (element == Element.INTERFACES) {
            interfaceNames = parseDomainInterfaces(reader, list);
            element = nextElement(reader);
        }
        if (element == Element.SOCKET_BINDING_GROUPS) {
            parseDomainSocketBindingGroups(reader, list, interfaceNames);
            element = nextElement(reader);
        }
        if (element == Element.SYSTEM_PROPERTIES) {
            parseDomainSystemProperties(reader, list);
            element = nextElement(reader);
        }
        if (element == Element.DEPLOYMENTS) {
            parseDeployments(reader, list, null);
            element = nextElement(reader);
        }
        if (element == Element.SERVER_GROUPS) {
            parseServerGroups(reader, list);
            element = nextElement(reader);
        }
        if (element != null) {
            throw unexpectedElement(reader);
        }
    }


    static Set<String> parseExtensions(final XMLExtendedStreamReader reader) throws XMLStreamException {
        requireNoAttributes(reader);

        final ExtensionContext extensionContext = new ExtensionContextImpl(reader);

        final Set<String> found = new LinkedHashSet<String>();

        while (reader.nextTag() != END_ELEMENT) {
            // Attribute && require no content
            final String moduleName = readStringAttributeElement(reader, Attribute.MODULE.getLocalName());

            if (! found.add(moduleName)) {
                // duplicate module name
                throw invalidAttributeValue(reader, 0);
            }

            // Register element handlers for this extension
            try {
               //for (Extension extension : Module.loadServiceFromCurrent(ModuleIdentifier.fromString(moduleName), Extension.class)) {
               Module module = Module.getModuleFromDefaultLoader(ModuleIdentifier.fromString(moduleName));
               for (Extension extension : module.loadService(Extension.class)) {
                    extension.initialize(extensionContext);
                }
            } catch (ModuleLoadException e) {
                throw new XMLStreamException("Failed to load module", e);
            }
        }

        return found;
    }

    static void parseProfiles(final XMLExtendedStreamReader reader, final List<? super AbstractDomainModelUpdate<?>> list) throws XMLStreamException {
        requireNoAttributes(reader);

        final Set<String> names = new HashSet<String>();

        while (reader.nextTag() != END_ELEMENT) {
            // Attributes
            requireSingleAttribute(reader, Attribute.NAME.getLocalName());
            final String name = reader.getAttributeValue(0);
            if (! names.add(name)) {
                throw new XMLStreamException("Duplicate profile declaration " + name, reader.getLocation());
            }

            list.add(new DomainProfileAdd(name));
            final Set<String> includes = new LinkedHashSet<String>();

            // Content
            // Sequence
            final Set<String> configuredSubsystemTypes = new HashSet<String>();
            while (reader.nextTag() != END_ELEMENT) {
                switch (Namespace.forUri(reader.getNamespaceURI())) {
                    case UNKNOWN: {
                        if (Element.forName(reader.getLocalName()) != Element.SUBSYSTEM) {
                            throw unexpectedElement(reader);
                        }
                        if (!configuredSubsystemTypes.add(reader.getNamespaceURI())) {
                            throw new XMLStreamException("Duplicate subsystem declaration", reader.getLocation());
                        }
                        // parse content
                        final ParseResult<ExtensionContext.SubsystemConfiguration<?>> result = new ParseResult<ExtensionContext.SubsystemConfiguration<?>>();
                        reader.handleAny(result);
                        list.add(new DomainSubsystemAdd(name, result.getResult().getSubsystemAdd()));
                        for (AbstractSubsystemUpdate<?, ?> update : result.getResult().getUpdates()) {
                            // I don't think this is really an unchecked cast (even though ? is bounded by Object, the class
                            // specifies an additional bound for E so it should be considered safe), but IDEA thinks it is...
                            //noinspection unchecked
                            list.add(DomainSubsystemUpdate.create(name, update));
                        }
                        break;
                    }
                    case DOMAIN_1_0: {
                        // include should come first
                        if (configuredSubsystemTypes.size() > 0) {
                            throw unexpectedElement(reader);
                        }
                        if (Element.forName(reader.getLocalName()) != Element.INCLUDE) {
                            throw unexpectedElement(reader);
                        }
                        final String includedName = readStringAttributeElement(reader, Attribute.PROFILE.getLocalName());
                        if (! names.contains(includedName)) {
                            throw new XMLStreamException("No profile found for inclusion", reader.getLocation());
                        }
                        if (! includes.add(includedName)) {
                            throw new XMLStreamException("Duplicate profile include", reader.getLocation());
                        }
                        list.add(new DomainProfileIncludeAdd(name, includedName));
                        break;
                    }
                    default: {
                        throw unexpectedElement(reader);
                    }
                }
            }

            if (configuredSubsystemTypes.size() == 0) {
                throw new XMLStreamException("Profile has no subsystem configurations", reader.getLocation());
            }
        }
    }

    static void parseServerProfile(final XMLExtendedStreamReader reader, List<? super AbstractServerModelUpdate<?>> list) throws XMLStreamException {
        // Attributes
        requireSingleAttribute(reader, Attribute.NAME.getLocalName());
        final String name = reader.getAttributeValue(0);

        list.add(new ServerProfileUpdate(name));

        // Content
        final Set<String> configuredSubsystemTypes = new HashSet<String>();
        while (reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case UNKNOWN: {
                    if (Element.forName(reader.getLocalName()) != Element.SUBSYSTEM) {
                        throw unexpectedElement(reader);
                    }
                    if (!configuredSubsystemTypes.add(reader.getNamespaceURI())) {
                        throw new XMLStreamException("Duplicate subsystem declaration", reader.getLocation());
                    }
                    // parse content
                    final ParseResult<ExtensionContext.SubsystemConfiguration<?>> result = new ParseResult<ExtensionContext.SubsystemConfiguration<?>>();
                    reader.handleAny(result);
                    list.add(new ServerSubsystemAdd(result.getResult().getSubsystemAdd()));
                    for (AbstractSubsystemUpdate<?, ?> update : result.getResult().getUpdates()) {
                        // I don't think this is really an unchecked cast (even though ? is bounded by Object, the class
                        // specifies an additional bound for E so it should be considered safe), but IDEA thinks it is...
                        //noinspection unchecked
                        list.add(ServerSubsystemUpdate.create(update));
                    }
                    break;
                }
                default: {
                    throw unexpectedElement(reader);
                }
            }
        }

        if (configuredSubsystemTypes.size() == 0) {
            throw new XMLStreamException("Profile has no subsystem configurations", reader.getLocation());
        }
    }

    static Set<String> parseHostInterfaces(final XMLExtendedStreamReader reader, final List<? super AbstractHostModelUpdate<?>> list) throws XMLStreamException {
        final List<InterfaceAdd> updates = new ArrayList<InterfaceAdd>();
        final Set<String> names = new HashSet<String>();
        parseInterfaces(reader, names, updates, true);
        for(final InterfaceAdd update : updates) {
            list.add(new HostInterfaceAdd(update));
        }
        return names;
    }

    static Set<String> parseServerElementInterfaces(final String serverName, final XMLExtendedStreamReader reader, final List<? super AbstractHostModelUpdate<?>> list) throws XMLStreamException {
        final List<InterfaceAdd> updates = new ArrayList<InterfaceAdd>();
        final Set<String> names = new HashSet<String>();
        parseInterfaces(reader, names, updates, true);
        for(final InterfaceAdd update : updates) {
            list.add(HostServerUpdate.create(serverName, new ServerElementInterfaceAdd(update)));
        }
        return names;
    }

    static Set<String> parseServerModelInterfaces(final XMLExtendedStreamReader reader, final List<? super AbstractServerModelUpdate<?>> list) throws XMLStreamException {
        final List<InterfaceAdd> updates = new ArrayList<InterfaceAdd>();
        final Set<String> names = new HashSet<String>();
        parseInterfaces(reader, names, updates, true);
        for(final InterfaceAdd update : updates) {
            list.add(new ServerModelInterfaceAdd(update));
        }
        return names;
    }

    static Set<String> parseDomainInterfaces(final XMLExtendedStreamReader reader, final List<? super AbstractDomainModelUpdate<?>> list) throws XMLStreamException {
        final List<InterfaceAdd> updates = new ArrayList<InterfaceAdd>();
        final Set<String> names = new HashSet<String>();
        parseInterfaces(reader, names, updates, false);
        for(final InterfaceAdd update : updates) {
            list.add(new DomainInterfaceAdd(update));
        }
        return names;
    }

    static Set<String> parseInterfaces(final XMLExtendedStreamReader reader, final Set<String> names, final List<InterfaceAdd> list, boolean checkSpecified) throws XMLStreamException {
        requireNoAttributes(reader);

        while (reader.nextTag() != END_ELEMENT) {
            // Attributes
            requireSingleAttribute(reader, Attribute.NAME.getLocalName());
            final String name = reader.getAttributeValue(0);
            if (! names.add(name)) {
                throw new XMLStreamException("Duplicate interface declaration", reader.getLocation());
            }

            // Content
            // nested choices
            if (reader.nextTag() == END_ELEMENT) {
                if(checkSpecified == false) {
                    // in the domain it does not need to be complete
                    continue;
                }
                throw unexpectedEndElement(reader);
            }

            final Map<Element, AbstractInterfaceCriteriaElement<?>> interfaceCriteria = new HashMap<Element, AbstractInterfaceCriteriaElement<?>>();
            boolean first = true;
            Element anyElement = null;
            do {
                if (Namespace.forUri(reader.getNamespaceURI()) != Namespace.DOMAIN_1_0) {
                    throw unexpectedElement(reader);
                }
                final Element element = Element.forName(reader.getLocalName());
                switch (element) {
                    case ANY_ADDRESS:
                    case ANY_IPV4_ADDRESS:
                    case ANY_IPV6_ADDRESS: {
                        if (! first || anyElement != null) {
                            throw unexpectedElement(reader);
                        }
                        requireNoAttributes(reader);
                        requireNoContent(reader);

                        // no others allowed
//                        if (reader.nextTag() != END_ELEMENT) {
//                            throw unexpectedElement(reader);
//                        }
                        // The any element
                        anyElement = element;
                        break;
                    } default: {
                        if (anyElement != null) {
                            throw unexpectedElement(reader);
                        }
                        switch (element) {
                            case ANY:
                            case NOT: {
                                final CompoundCriteriaElement criteria = InterfaceParsingUtils.createCompoundCriteria(reader, element == Element.ANY);
                                interfaceCriteria.put(element, criteria);
                                break;
                            } default: {
                                final AbstractInterfaceCriteriaElement<?> criteria = InterfaceParsingUtils.parseSimpleInterfaceCriteria(reader, element);
                                interfaceCriteria.put(element, criteria);
                            }
                        }
                    }
                }
                first = false;
            } while (reader.nextTag() != END_ELEMENT);
            if (checkSpecified && anyElement == null && interfaceCriteria.isEmpty()) {
                throw new XMLStreamException("Either an inet-address element or some other interface criteria element is required", reader.getLocation());
            }
            // Domain interface update
            list.add(new InterfaceAdd(name,
                    anyElement == Element.ANY_IPV4_ADDRESS,
                    anyElement == Element.ANY_IPV6_ADDRESS,
                    anyElement == Element.ANY_ADDRESS,
                    interfaceCriteria.values()));
        }
        return names;
    }

    static void parseDomainSocketBindingGroups(final XMLExtendedStreamReader reader, final List<? super AbstractDomainModelUpdate<?>> list, Set<String> interfaces) throws XMLStreamException {
        final Set<String> groupNames = new HashSet<String>();
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case DOMAIN_1_0: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case SOCKET_BINDING_GROUP: {
                            final List<SocketBindingAdd> bindingUpdates = new ArrayList<SocketBindingAdd>();
                            // parse binding-group
                            final SocketBindingGroupUpdate group = parseSocketBindingGroup(reader, bindingUpdates, interfaces, true);
                            final String name = group.getName();
                            if(groupNames.add(name)) {
                                ParseUtils.unexpectedElement(reader);
                            }
                            // Create domain updates
                            list.add(new DomainSocketBindingGroupAdd(group));
                            for(final SocketBindingAdd bindingUpdate : bindingUpdates) {
                                list.add(new DomainSocketBindingUpdate(name, bindingUpdate));
                            }

                            break;
                        } default: {
                            throw ParseUtils.unexpectedElement(reader);
                        }
                    }
                    break;
                } default: {
                    throw ParseUtils.unexpectedElement(reader);
                }
            }
        }
    }

    static SocketBindingGroupUpdate parseSocketBindingGroup(final XMLExtendedStreamReader reader, List<SocketBindingAdd> bindingUpdates, Set<String> interfaces, boolean allowInclude) throws XMLStreamException {
        String name = null;
        String defIntf = null;
        Set<String> includedGroups = new HashSet<String>();
        Set<String> socketBindings = new HashSet<String>();

        // Handle attributes
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw ParseUtils.unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case NAME: {
                        name = value;
                        break;
                    }
                    case DEFAULT_INTERFACE: {
                        if (! interfaces.contains(value)) {
                            throw new XMLStreamException("Unknown interface " + value +
                                    " " + attribute.getLocalName() + " must be declared in element " +
                                    Element.INTERFACES.getLocalName(), reader.getLocation());
                        }
                        defIntf = value;
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedAttribute(reader, i);
                }
            }
        }
        if (name == null) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.NAME));
        }
        if (defIntf == null) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.DEFAULT_INTERFACE));
        }
        // Handle elements
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case DOMAIN_1_0: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case INCLUDE: {
                            if(! allowInclude) {
                                // no include in standalone
                                throw ParseUtils.unexpectedElement(reader);
                            }
                            final String includedGroup = ParseUtils.readStringAttributeElement(reader, Attribute.SOCKET_BINDING_GROUP.getLocalName());
                            if (includedGroups.contains(includedGroup)) {
                                throw new XMLStreamException("Included socket-binding-group " + includedGroup + " already declared", reader.getLocation());
                            }
                            includedGroups.add(includedGroup);
                            break;
                        }
                        case SOCKET_BINDING: {
                            final String bindingName = parseSocketBinding(reader, interfaces, bindingUpdates, defIntf);
                            if (socketBindings.contains(bindingName)) {
                                throw new XMLStreamException("socket-binding " + bindingName + " already declared", reader.getLocation());
                            }
                            socketBindings.add(bindingName);
                            break;
                        }
                        default:
                            throw ParseUtils.unexpectedElement(reader);
                    }
                    break;
                }
                default:
                    throw ParseUtils.unexpectedElement(reader);
            }
        }
        return new SocketBindingGroupUpdate(name, defIntf, includedGroups);
    }

    static String parseSocketBinding(final XMLExtendedStreamReader reader, Set<String> interfaces, List<SocketBindingAdd> updates, final String inheritedInterfaceName) throws XMLStreamException {

        String name = null;
        String interfaceName = null;
        Integer port = null;
        Boolean fixPort = null;
        InetAddress mcastAddr = null;
        Integer mcastPort = null;

        // Handle attributes
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw ParseUtils.unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case NAME: {
                        name = value;
                        break;
                    }
                    case INTERFACE: {
                        if (! interfaces.contains(value)) {
                            throw new XMLStreamException("Unknown interface " + value +
                                    " " + attribute.getLocalName() + " must be declared in element " +
                                    Element.INTERFACES.getLocalName(), reader.getLocation());
                        }
                        interfaceName = value;
                        break;
                    }
                    case PORT: {
                        port = Integer.valueOf(parsePort(value, attribute, reader, true));
                        break;
                    }
                    case FIXED_PORT: {
                        fixPort = Boolean.valueOf(value);
                        break;
                    }
                    case MULTICAST_ADDRESS: {
                        try {
                            mcastAddr = InetAddress.getByName(value);
                            if (!mcastAddr.isMulticastAddress()) {
                                throw new XMLStreamException("Value " + value + " for attribute " +
                                        attribute.getLocalName() + " is not a valid multicast address",
                                        reader.getLocation());
                            }
                        } catch (UnknownHostException e) {
                            throw new XMLStreamException("Value " + value + " for attribute " +
                                    attribute.getLocalName() + " is not a valid multicast address",
                                    reader.getLocation(), e);
                        }
                    }
                    case MULTICAST_PORT: {
                        mcastPort = Integer.valueOf(parsePort(value, attribute, reader, false));
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedAttribute(reader, i);
                }
            }
        }
        if (name == null) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.NAME));
        }
        // Handle elements
        ParseUtils.requireNoContent(reader);

        final SocketBindingAdd update = new SocketBindingAdd(interfaceName == null ? inheritedInterfaceName : interfaceName, name, port == null ? 0 : port.intValue());
        update.setFixedPort(fixPort == null ? false : fixPort.booleanValue());
        update.setMulticastAddress(mcastAddr);
        update.setMulticastPort(mcastAddr == null ? -1 : mcastPort != null ? mcastPort.intValue() : -1);
        updates.add(update);
        return name;
    }

    static void parseDeployments(final XMLExtendedStreamReader reader, final List<? super AbstractDomainModelUpdate<?>> list, final String serverGroupName) throws XMLStreamException {
        requireNoAttributes(reader);

        final Set<String> names = new HashSet<String>();

        while (reader.nextTag() != END_ELEMENT) {
            // Handle attributes
            String uniqueName = null;
            String runtimeName = null;
            byte[] hash = null;
            String startInput = null;
            final int count = reader.getAttributeCount();
            for (int i = 0; i < count; i ++) {
                final String value = reader.getAttributeValue(i);
                if (reader.getAttributeNamespace(i) != null) {
                    throw ParseUtils.unexpectedAttribute(reader, i);
                } else {
                    final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                    switch (attribute) {
                        case NAME: {
                            if (!names.add(value)) {
                                throw ParseUtils.duplicateNamedElement(reader, value);
                            }
                            uniqueName = value;
                            break;
                        }
                        case RUNTIME_NAME: {
                            runtimeName = value;
                            break;
                        }
                        case SHA1: {
                            try {
                                hash = ParseUtils.hexStringToByteArray(value);
                            }
                            catch (Exception e) {
                               throw new XMLStreamException("Value " + value +
                                       " for attribute " + attribute.getLocalName() +
                                       " does not represent a properly hex-encoded SHA1 hash",
                                       reader.getLocation(), e);
                            }
                            break;
                        }
                        case ALLOWED: {
                            if (! Boolean.parseBoolean(value)) {
                                throw new XMLStreamException("Attribute '" + attribute.getLocalName() + "' is not allowed", reader.getLocation());
                            }
                            break;
                        }
                        case START: {
                            startInput = value;
                            break;
                        }
                        default:
                            throw ParseUtils.unexpectedAttribute(reader, i);
                    }
                }
            }
            if (uniqueName == null) {
                throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.NAME));
            }
            if (runtimeName == null) {
                throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.RUNTIME_NAME));
            }
            if (hash == null) {
                throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.SHA1));
            }
            boolean toStart = startInput == null ? true : Boolean.parseBoolean(startInput);

            // Handle elements
            ParseUtils.requireNoContent(reader);

            if (serverGroupName == null) {
                list.add(new DomainDeploymentAdd(uniqueName, runtimeName, hash, toStart));
            }
            else {
                list.add(DomainServerGroupUpdate.create(serverGroupName, new ServerGroupDeploymentAdd(uniqueName, runtimeName, hash, toStart)));
            }
        }
    }

    static void parseServerDeployments(final XMLExtendedStreamReader reader, final List<? super AbstractServerModelUpdate<?>> list) throws XMLStreamException {
        requireNoAttributes(reader);

        final Set<String> names = new HashSet<String>();

        while (reader.nextTag() != END_ELEMENT) {
            // Handle attributes
            String uniqueName = null;
            String runtimeName = null;
            byte[] hash = null;
            String startInput = null;
            final int count = reader.getAttributeCount();
            for (int i = 0; i < count; i ++) {
                final String value = reader.getAttributeValue(i);
                if (reader.getAttributeNamespace(i) != null) {
                    throw ParseUtils.unexpectedAttribute(reader, i);
                } else {
                    final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                    switch (attribute) {
                        case NAME: {
                            if (!names.add(value)) {
                                throw ParseUtils.duplicateNamedElement(reader, value);
                            }
                            uniqueName = value;
                            break;
                        }
                        case RUNTIME_NAME: {
                            runtimeName = value;
                            break;
                        }
                        case SHA1: {
                            try {
                                hash = ParseUtils.hexStringToByteArray(value);
                            }
                            catch (Exception e) {
                               throw new XMLStreamException("Value " + value +
                                       " for attribute " + attribute.getLocalName() +
                                       " does not represent a properly hex-encoded SHA1 hash",
                                       reader.getLocation(), e);
                            }
                            break;
                        }
                        case ALLOWED: {
                            if (!Boolean.parseBoolean(value)) {
                                throw new XMLStreamException("Attribute '" + attribute.getLocalName() + "' is not allowed", reader.getLocation());
                            }
                            break;
                        }
                        case START: {
                            startInput = value;
                            break;
                        }
                        default:
                            throw ParseUtils.unexpectedAttribute(reader, i);
                    }
                }
            }
            if (uniqueName == null) {
                throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.NAME));
            }
            if (runtimeName == null) {
                throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.RUNTIME_NAME));
            }
            if (hash == null) {
                throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.SHA1));
            }
            boolean toStart = startInput == null ? true : Boolean.parseBoolean(startInput);

            // Handle elements
            ParseUtils.requireNoContent(reader);

            list.add(new ServerModelDeploymentAdd(uniqueName, runtimeName, hash));
            list.add(new ServerModelDeploymentStartStopUpdate(uniqueName, toStart));
        }
    }

    static void parseServerGroups(final XMLExtendedStreamReader reader, final List<? super AbstractDomainModelUpdate<?>> list) throws XMLStreamException {
        requireNoAttributes(reader);

        final Set<String> names = new HashSet<String>();

        while (reader.nextTag() != END_ELEMENT) {

            String name = null;
            String profile = null;
            Collection<PropertyAdd> systemProperties = null;

            // Handle attributes
            final int count = reader.getAttributeCount();
            for (int i = 0; i < count; i ++) {
                final String value = reader.getAttributeValue(i);
                if (reader.getAttributeNamespace(i) != null) {
                    throw ParseUtils.unexpectedAttribute(reader, i);
                } else {
                    final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                    switch (attribute) {
                        case NAME: {
                            if (name != null) {
                                throw ParseUtils.duplicateAttribute(reader, attribute.getLocalName());
                            }
                            if (!names.add(value)) {
                                throw ParseUtils.duplicateNamedElement(reader, value);
                            }
                            name = value;
                            break;
                        }
                        case PROFILE: {
                            if (profile != null) {
                                throw ParseUtils.duplicateAttribute(reader, attribute.getLocalName());
                            }
                            profile = value;
                            break;
                        }
                        default:
                            throw ParseUtils.unexpectedAttribute(reader, i);
                    }
                }
            }
            if (name == null) {
                throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.NAME));
            }
            if (profile == null) {
                throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.PROFILE));
            }

            list.add(new DomainServerGroupAdd(name, profile));

            // Handle elements

            NamedModelUpdates<JvmElement> jvm = null;
            NameOffset socketBinding = null;
            boolean sawDeployments = false;
            while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
                switch (Namespace.forUri(reader.getNamespaceURI())) {
                    case DOMAIN_1_0: {
                        final Element element = Element.forName(reader.getLocalName());
                        switch (element) {
                            case JVM: {
                                if (jvm != null) {
                                    throw new XMLStreamException(element.getLocalName() + " already defined", reader.getLocation());
                                }
                                jvm = parseJvm(reader);
                                list.add(DomainServerGroupUpdate.create(name, new ServerGroupJvmAdd(jvm.name)));
                                for (AbstractModelUpdate<JvmElement, ?> update : jvm.updates) {
                                    list.add(DomainServerGroupUpdate.create(name, ServerGroupJvmUpdate.create(update)));
                                }
                                break;
                            }
                            case SOCKET_BINDING_GROUP: {
                                if (socketBinding != null) {
                                    throw new XMLStreamException(element.getLocalName() + " already defined", reader.getLocation());
                                }
                                socketBinding = parseSocketBindingGroupRef(reader);
                                list.add(DomainServerGroupUpdate.create(name, new ServerGroupSocketBindingGroupUpdate(socketBinding.name)));
                                if (socketBinding.offset > 0) {
                                    list.add(DomainServerGroupUpdate.create(name, new ServerGroupSocketBindingPortOffsetUpdate(socketBinding.offset)));
                                }
                                break;
                            }
                            case DEPLOYMENTS: {
                                if (sawDeployments) {
                                    throw new XMLStreamException(element.getLocalName() + " already defined", reader.getLocation());
                                }
                                sawDeployments = true;
                                parseDeployments(reader, list, name);
                                break;
                            }
                            case SYSTEM_PROPERTIES: {
                                if (systemProperties != null) {
                                    throw new XMLStreamException(element.getLocalName() + " already declared", reader.getLocation());
                                }
                                systemProperties = parseProperties(reader, Element.PROPERTY, true);
                                for(final PropertyAdd propertyUpdate : systemProperties) {
                                    list.add(DomainServerGroupUpdate.create(name, new ServerGroupPropertiesUpdate(name, propertyUpdate)));
                                }
                                break;
                            }
                            default:
                                throw ParseUtils.unexpectedElement(reader);
                        }
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedElement(reader);
                }
            }
        }
    }

    static void parseDomainSystemProperties(final XMLExtendedStreamReader reader, final List<? super AbstractDomainModelUpdate<?>> list) throws XMLStreamException {
        for(final PropertyAdd propertyUpdate : parseProperties(reader, Element.PROPERTY, true)) {
            list.add(new DomainSystemPropertyUpdate(propertyUpdate));
        }
    }

    static void parseHostSystemProperties(final XMLExtendedStreamReader reader, final List<? super AbstractHostModelUpdate<?>> list) throws XMLStreamException {
        for(final PropertyAdd propertyUpdate : parseProperties(reader, Element.PROPERTY, true)) {
            list.add(new HostSystemPropertyUpdate(propertyUpdate));
        }
    }

    static void parseServerModelSystemProperties(final XMLExtendedStreamReader reader, final List<? super AbstractServerModelUpdate<?>> list) throws XMLStreamException {
        for(final PropertyAdd propertyUpdate : parseProperties(reader, Element.PROPERTY, true)) {
            list.add(new ServerSystemPropertyUpdate(propertyUpdate));
        }
    }

    static Collection<PropertyAdd> parseProperties(final XMLExtendedStreamReader reader, final Element propertyType, final boolean allowNullValue) throws XMLStreamException {
        Map<String, PropertyAdd> properties = new HashMap<String, PropertyAdd>();
        // Handle attributes
        ParseUtils.requireNoAttributes(reader);
        // Handle elements
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case DOMAIN_1_0: {
                    final Element element = Element.forName(reader.getLocalName());
                    if (element == propertyType) {
                        // Handle attributes
                        String name = null;
                        String value = null;
                        int count = reader.getAttributeCount();
                        for (int i = 0; i < count; i++) {
                            final String attrValue = reader.getAttributeValue(i);
                            if (reader.getAttributeNamespace(i) != null) {
                                throw ParseUtils.unexpectedAttribute(reader, i);
                            }
                            else {
                                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                                switch (attribute) {
                                    case NAME: {
                                        name = attrValue;
                                        if (properties.containsKey(name)) {
                                            throw new XMLStreamException("Property " + name + " already exists", reader.getLocation());
                                        }
                                        break;
                                    }
                                    case VALUE: {
                                        value = attrValue;
                                        break;
                                    }
                                    default:
                                        throw ParseUtils.unexpectedAttribute(reader, i);
                                }
                            }
                        }
                        if (name == null) {
                            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.NAME));
                        }
                        if (value == null && !allowNullValue) {
                            throw new XMLStreamException("Value for property " + name + " is null", reader.getLocation());
                        }
                        // PropertyAdd
                        properties.put(name, new PropertyAdd(name, value));
                        // Handle elements
                        ParseUtils.requireNoContent(reader);
                    } else {
                        throw ParseUtils.unexpectedElement(reader);
                    }
                    break;
                }
                default:
                    throw ParseUtils.unexpectedElement(reader);
            }
        }
        if (properties.size() == 0) {
            throw ParseUtils.missingRequiredElement(reader, Collections.singleton(propertyType));
        }
        return properties.values();
    }

    static void parseJvms(final XMLExtendedStreamReader reader, final List<? super AbstractHostModelUpdate<?>> list) throws XMLStreamException {

        requireNoAttributes(reader);

        Set<String> names = new HashSet<String>();
        // Handle elements
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case DOMAIN_1_0: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case JVM:
                            NamedModelUpdates<JvmElement> jvm = parseJvm(reader, names);
                            list.add(new HostJvmAdd(jvm.name));
                            for (AbstractModelUpdate<JvmElement, ?> update : jvm.updates) {
                                list.add(HostJvmUpdate.create(jvm.name, update));
                            }
                            break;
                        default:
                            throw unexpectedElement(reader);
                    }
                    break;
                }
                default: {
                    throw unexpectedElement(reader);
                }
            }
        }
    }

    static NamedModelUpdates<JvmElement> parseJvm(final XMLExtendedStreamReader reader) throws XMLStreamException {
        Set<String> empty = new HashSet<String>();
        return parseJvm(reader, empty);
    }

    static NamedModelUpdates<JvmElement> parseJvm(final XMLExtendedStreamReader reader, Set<String> jvmNames) throws XMLStreamException {

        List<AbstractModelUpdate<JvmElement, ?>> updates = new ArrayList<AbstractModelUpdate<JvmElement, ?>>();

        // Handle attributes
        String name = null;
        String type = null;
        String home = null;
        Boolean debugEnabled = null;
        String debugOptions = null;
        Boolean envClasspathIgnored = null;
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw ParseUtils.unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case NAME: {
                        if (name != null)
                            throw ParseUtils.duplicateAttribute(reader, attribute.getLocalName());

                        if (!jvmNames.add(value)) {
                            throw new XMLStreamException("Duplicate JVM declaration " + value, reader.getLocation());
                        }
                        name = value;
                        break;
                    }
                    case JAVA_HOME: {
                        if (home != null)
                            throw ParseUtils.duplicateAttribute(reader, attribute.getLocalName());
                        home = value;
                        updates.add(new JvmHomeUpdate(value));
                        break;
                    }
                    case TYPE: {
                        if (type != null)
                            throw ParseUtils.duplicateAttribute(reader, attribute.getLocalName());
                        type = value;

                        JvmType jvmType;
                        try {
                            jvmType = Enum.valueOf(JvmType.class, value);
                        } catch (IllegalArgumentException e) {
                            throw ParseUtils.invalidAttributeValue(reader, i);
                        }

                        updates.add(new JvmTypeUpdate(jvmType));
                        break;
                    }
                    case DEBUG_ENABLED: {
                        if (debugEnabled != null)
                            throw ParseUtils.duplicateAttribute(reader, attribute.getLocalName());
                        debugEnabled = Boolean.valueOf(value);
                        updates.add(new JvmDebugEnabledUpdate(debugEnabled));
                        break;
                    }
                    case DEBUG_OPTIONS: {
                        if (debugOptions != null)
                            throw ParseUtils.duplicateAttribute(reader, attribute.getLocalName());
                        debugOptions = value;
                        updates.add(new JvmDebugOptionsUpdate(value));
                        break;
                    }
                    case ENV_CLASSPATH_IGNORED: {
                        if (envClasspathIgnored != null)
                            throw ParseUtils.duplicateAttribute(reader, attribute.getLocalName());
                        envClasspathIgnored = Boolean.valueOf(value);
                        updates.add(new JvmEnvClasspathIgnoredUpdate(envClasspathIgnored));
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedAttribute(reader, i);
                }
            }
        }
        if (name == null) {
            // FIXME and fix xsd. A name is only required at domain and host
            // level (i.e. when wrapped in <jvms/>). At server-group and server
            // levels it can be unnamed, in which case configuration from
            // domain and host levels aren't mixed in. OR make name required in xsd always
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.NAME));
        }
        if (type == null) {
            updates.add(new JvmTypeUpdate(JvmType.SUN));
        }

        // Handle elements
        Collection<JvmOptionAdd> jvmOptions = null;
        Collection<PropertyAdd> environmentVariables = null;
        Collection<PropertyAdd> systemProperties = null;
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case DOMAIN_1_0: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case HEAP: {
                            updates.addAll(parseHeap(reader));
                            break;
                        }
                        case PERMGEN: {
                            updates.addAll(parsePermgen(reader));
                            break;
                        }
                        case STACK: {
                            updates.addAll(parseStack(reader));
                            break;
                        }
                        case AGENT_LIB: {
                            updates.addAll(parseAgentLib(reader));
                            break;
                        }
                        case AGENT_PATH: {
                            updates.addAll(parseAgentPath(reader));
                            break;
                        }
                        case JAVA_AGENT: {
                            updates.addAll(parseJavaagent(reader));
                            break;
                        }
                        case ENVIRONMENT_VARIABLES: {
                            if (environmentVariables != null) {
                                throw new XMLStreamException(element.getLocalName() + " already declared", reader.getLocation());
                            }
                            environmentVariables = parseProperties(reader, Element.VARIABLE, true);
                            for (PropertyAdd propAdd : environmentVariables) {
                                updates.add(new JvmEnvironmentVariableUpdate(propAdd));
                            }
                            break;
                        }
                        case SYSTEM_PROPERTIES: {
                            if (systemProperties != null) {
                                throw new XMLStreamException(element.getLocalName() + " already declared", reader.getLocation());
                            }
                            systemProperties = parseProperties(reader, Element.PROPERTY, true);
                            for (PropertyAdd propAdd : systemProperties) {
                                updates.add(new JvmSystemPropertiesUpdate(propAdd));
                            }
                            break;
                        }
                        case JVM_OPTIONS: {
                            if (jvmOptions != null) {
                                throw new XMLStreamException(element.getLocalName() + " already declared", reader.getLocation());
                            }
                            jvmOptions = parseJvmOptions(reader);
                            for (JvmOptionAdd optAdd : jvmOptions) {
                                updates.add(new JvmOptionsUpdate(optAdd));
                            }
                            break;
                        }
                        default:
                            throw ParseUtils.unexpectedElement(reader);
                    }
                    break;
                }
                default:
                    throw ParseUtils.unexpectedElement(reader);
            }
        }
        return new NamedModelUpdates<JvmElement>(name, updates);
    }

    static List<AbstractModelUpdate<JvmElement, ?>> parseHeap(XMLExtendedStreamReader reader) throws XMLStreamException {
        List<AbstractModelUpdate<JvmElement, ?>> updates = new ArrayList<AbstractModelUpdate<JvmElement, ?>>();
        // Handle attributes
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw ParseUtils.unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case SIZE: {
                        updates.add(new JvmHeapUpdate(value));
                        break;
                    }
                    case MAX_SIZE: {
                        updates.add(new JvmMaxHeapUpdate(value));
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedAttribute(reader, i);
                }
            }
        }
        // Handle elements
        ParseUtils.requireNoContent(reader);
        return updates;
    }

    static List<AbstractModelUpdate<JvmElement, ?>> parsePermgen(XMLExtendedStreamReader reader) throws XMLStreamException {
        List<AbstractModelUpdate<JvmElement, ?>> updates = new ArrayList<AbstractModelUpdate<JvmElement, ?>>();
        // Handle attributes
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw ParseUtils.unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case SIZE: {
                        updates.add(new JvmPermgenUpdate(value));
                        break;
                    }
                    case MAX_SIZE: {
                        updates.add(new JvmMaxPermgenUpdate(value));
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedAttribute(reader, i);
                }
            }
        }
        // Handle elements
        ParseUtils.requireNoContent(reader);
        return updates;
    }

    static List<AbstractModelUpdate<JvmElement, ?>> parseStack(XMLExtendedStreamReader reader) throws XMLStreamException {
        List<AbstractModelUpdate<JvmElement, ?>> updates = new ArrayList<AbstractModelUpdate<JvmElement, ?>>();
        // Handle attributes
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw ParseUtils.unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case SIZE: {
                        updates.add(new JvmStackUpdate(value));
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedAttribute(reader, i);
                }
            }
        }
        if (updates.size() == 0) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.SIZE));
        }
        // Handle elements
        ParseUtils.requireNoContent(reader);
        return updates;
    }

    static List<AbstractModelUpdate<JvmElement, ?>> parseAgentLib(XMLExtendedStreamReader reader) throws XMLStreamException {
        List<AbstractModelUpdate<JvmElement, ?>> updates = new ArrayList<AbstractModelUpdate<JvmElement, ?>>();
        // Handle attributes
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw ParseUtils.unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case VALUE: {
                        updates.add(new JvmAgentLibUpdate(value));
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedAttribute(reader, i);
                }
            }
        }
        if (updates.size() == 0) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.VALUE));
        }
        // Handle elements
        ParseUtils.requireNoContent(reader);
        return updates;
    }

    static List<AbstractModelUpdate<JvmElement, ?>> parseAgentPath(XMLExtendedStreamReader reader) throws XMLStreamException {
        List<AbstractModelUpdate<JvmElement, ?>> updates = new ArrayList<AbstractModelUpdate<JvmElement, ?>>();
        // Handle attributes
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw ParseUtils.unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case VALUE: {
                        updates.add(new JvmAgentPathUpdate(value));
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedAttribute(reader, i);
                }
            }
        }
        if (updates.size() == 0) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.VALUE));
        }
        // Handle elements
        ParseUtils.requireNoContent(reader);
        return updates;
    }

    static List<AbstractModelUpdate<JvmElement, ?>> parseJavaagent(XMLExtendedStreamReader reader) throws XMLStreamException {
        List<AbstractModelUpdate<JvmElement, ?>> updates = new ArrayList<AbstractModelUpdate<JvmElement, ?>>();
        // Handle attributes
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw ParseUtils.unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case VALUE: {
                        updates.add(new JvmJavaagentUpdate(value));
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedAttribute(reader, i);
                }
            }
        }
        if (updates.size() == 0) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.VALUE));
        }
        // Handle elements
        ParseUtils.requireNoContent(reader);
        return updates;
    }

    static Collection<JvmOptionAdd> parseJvmOptions(final XMLExtendedStreamReader reader) throws XMLStreamException {
        List<JvmOptionAdd> options = new ArrayList<JvmOptionAdd>();
        // Handle attributes
        ParseUtils.requireNoAttributes(reader);
        // Handle elements
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case DOMAIN_1_0: {
                    final Element element = Element.forName(reader.getLocalName());
                    if (element == Element.OPTION) {
                        // Handle attributes
                        String option = null;
                        int count = reader.getAttributeCount();
                        for (int i = 0; i < count; i++) {
                            final String attrValue = reader.getAttributeValue(i);
                            if (reader.getAttributeNamespace(i) != null) {
                                throw ParseUtils.unexpectedAttribute(reader, i);
                            }
                            else {
                                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                                switch (attribute) {
                                    case VALUE: {
                                        option = attrValue;
                                        break;
                                    }
                                    default:
                                        throw ParseUtils.unexpectedAttribute(reader, i);
                                }
                            }
                        }
                        if (option == null) {
                            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.NAME));
                        }

                        // PropertyAdd
                        options.add(new JvmOptionAdd(option));
                        // Handle elements
                        ParseUtils.requireNoContent(reader);
                    } else {
                        throw ParseUtils.unexpectedElement(reader);
                    }
                    break;
                }
                default:
                    throw ParseUtils.unexpectedElement(reader);
            }
        }
        if (options.size() == 0) {
            throw ParseUtils.missingRequiredElement(reader, Collections.singleton(Element.OPTION));
        }
        return options;
    }

    static NameOffset parseSocketBindingGroupRef(final XMLExtendedStreamReader reader) throws XMLStreamException {
        // Handle attributes
        String name = null;
        int offset = -1;
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw ParseUtils.unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case REF: {
                        if (name != null)
                            throw ParseUtils.duplicateAttribute(reader, attribute.getLocalName());
                        name = value;
                        break;
                    }
                    case PORT_OFFSET: {
                        try {
                            if (offset != -1)
                                throw ParseUtils.duplicateAttribute(reader, attribute.getLocalName());
                            offset = Integer.parseInt(value);
                            if (offset < 0) {
                                throw new XMLStreamException(offset + " is not a valid " +
                                        attribute.getLocalName() + " -- must be greater than zero",
                                        reader.getLocation());
                            }
                        } catch (NumberFormatException e) {
                            throw new XMLStreamException(offset + " is not a valid " +
                                    attribute.getLocalName(), reader.getLocation(), e);
                        }
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedAttribute(reader, i);
                }
            }
        }
        if (name == null) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.REF));
        }
        // Handle elements
        ParseUtils.requireNoContent(reader);

        return new NameOffset(name, offset);
    }

    static void parseManagement(final XMLExtendedStreamReader reader,
            final List<? super AbstractHostModelUpdate<?>> list) throws XMLStreamException {

        // Handle attributes
        String interfaceName = null;
        int port = 0;
        int maxThreads = -1;
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw ParseUtils.unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case INTERFACE: {
                        interfaceName = value;
                        break;
                    }
                    case PORT: {
                        port = Integer.parseInt(value);
                        if (port < 0) {
                            throw new XMLStreamException("Illegal '" + attribute.getLocalName() +
                                    "' value " + port + " -- cannot be negative",
                                    reader.getLocation());
                        }
                        break;
                    }
                    case MAX_THREADS: {
                        maxThreads = Integer.parseInt(value);
                        if (maxThreads < 1) {
                            throw new XMLStreamException("Illegal '" + attribute.getLocalName() +
                                    "' value " + maxThreads + " -- must be greater than 0",
                                    reader.getLocation());
                        }
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedAttribute(reader, i);
                }
            }
        }
        if(interfaceName == null) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.INTERFACE.getLocalName()));
        }
        list.add(new HostManagementSocketAdd(interfaceName, port));

        if (maxThreads > 0) {
            list.add(new HostManagementSocketThreadsUpdate(maxThreads));
        }
        reader.discardRemainder();
    }

    static void parseServerManagement(final XMLExtendedStreamReader reader,
            final List<? super AbstractServerModelUpdate<?>> list) throws XMLStreamException {

        // Handle attributes
        String interfaceName = null;
        int port = 0;
        int maxThreads = -1;
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw ParseUtils.unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case INTERFACE: {
                        interfaceName = value;
                        break;
                    }
                    case PORT: {
                        port = Integer.parseInt(value);
                        if (port < 0) {
                            throw new XMLStreamException("Illegal '" + attribute.getLocalName() +
                                    "' value " + port + " -- cannot be negative",
                                    reader.getLocation());
                        }
                        break;
                    }
                    case MAX_THREADS: {
                        maxThreads = Integer.parseInt(value);
                        if (maxThreads < 1) {
                            throw new XMLStreamException("Illegal '" + attribute.getLocalName() +
                                    "' value " + maxThreads + " -- must be greater than 0",
                                    reader.getLocation());
                        }
                        break;
                    }
                    default:
                        throw ParseUtils.unexpectedAttribute(reader, i);
                }
            }
        }
        if(interfaceName == null) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.INTERFACE.getLocalName()));
        }
        list.add(new ServerModelManagementSocketAdd(interfaceName, port));

        if (maxThreads > 0) {
            list.add(new ServerModelManagementSocketThreadsUpdate(maxThreads));
        }
        reader.discardRemainder();
    }

    static void parseDomainController(final XMLExtendedStreamReader reader,
            final List<? super AbstractHostModelUpdate<?>> list) throws XMLStreamException {

        requireNoAttributes(reader);

        boolean hasLocal = false;
        boolean hasRemote = false;
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case DOMAIN_1_0: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case LOCAL: {
                            if (hasLocal) {
                                throw new XMLStreamException("Child " + element.getLocalName() +
                                        " of element " + Element.DOMAIN_CONTROLLER.getLocalName() +
                                        " already declared", reader.getLocation());
                            }
                            else if (hasRemote) {
                                throw new XMLStreamException("Child " + Element.REMOTE.getLocalName() +
                                        " of element " + Element.DOMAIN_CONTROLLER.getLocalName() +
                                        " already declared", reader.getLocation());
                            }
                            requireNoAttributes(reader);
                            requireNoContent(reader);
                            list.add(new HostLocalDomainControllerAdd());
                            hasLocal = true;
                            break;
                        }
                        case REMOTE: {
                            if (hasRemote) {
                                throw new XMLStreamException("Child " + element.getLocalName() +
                                        " of element " + Element.DOMAIN_CONTROLLER.getLocalName() +
                                        " already declared", reader.getLocation());
                            }
                            else if (hasLocal) {
                                throw new XMLStreamException("Child " + Element.LOCAL.getLocalName() +
                                        " of element " + Element.DOMAIN_CONTROLLER.getLocalName() +
                                        " already declared", reader.getLocation());
                            }
                            parseRemoteDomainController(reader, list);
                            hasRemote = true;
                            break;
                        }
                        default: throw unexpectedElement(reader);
                    }
                    break;
                }
                default: throw unexpectedElement(reader);
            }
        }
        if (!hasLocal && !hasRemote) {
            throw new XMLStreamException("Either a " + Element.REMOTE.getLocalName() + " or " +
                    Element.LOCAL.getLocalName() + " domain controller configuration must be declared.", reader.getLocation());
        }
    }

    static void parseRemoteDomainController(XMLExtendedStreamReader reader,
            List<? super AbstractHostModelUpdate<?>> list) throws XMLStreamException {
        // Handle attributes
        String host = null;
        Integer port = null;
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case HOST: {
                        host = value;
                        break;
                    }
                    case PORT: {
                        port = Integer.valueOf(value);
                        if (port < 1) {
                            throw new XMLStreamException("Illegal '" + attribute.getLocalName() +
                                    "' value " + port + " -- cannot be less than one",
                                    reader.getLocation());
                        }
                        break;
                    }
                    default: throw unexpectedAttribute(reader, i);
                }
            }
        }
        if(host == null) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.HOST.getLocalName()));
        }
        if(port == null) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.PORT.getLocalName()));
        }

        list.add(new HostRemoteDomainControllerAdd(host, port.intValue()));

        reader.discardRemainder();
    }

    static void parseServers(final XMLExtendedStreamReader reader, final List<? super AbstractHostModelUpdate<?>> list) throws XMLStreamException {

        requireNoAttributes(reader);
        // Handle elements
        Set<String> names = new HashSet<String>();
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case DOMAIN_1_0: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case SERVER:
                            parseServer(reader, list, names);
                            break;
                        default:
                            throw unexpectedElement(reader);
                    }
                    break;
                }
                default: {
                    throw unexpectedElement(reader);
                }
            }
        }
    }

    static void parseServer(final XMLExtendedStreamReader reader, final List<? super AbstractHostModelUpdate<?>> list, Set<String> serverNames) throws XMLStreamException {
        // Handle attributes
        String name = null;
        String group = null;
        Boolean start = null;
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case NAME: {
                        if (!serverNames.add(value)) {
                            throw new XMLStreamException("Duplicate server declaration " + value, reader.getLocation());
                        }
                        name = value;
                        break;
                    }
                    case GROUP: {
                        group = value;
                        break;
                    }
                    case START: {
                        start = Boolean.valueOf(value);
                        break;
                    }
                    default: throw unexpectedAttribute(reader, i);
                }
            }
        }
        if (name == null) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.NAME));
        }
        if (group == null) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.GROUP));
        }
        list.add(new HostServerAdd(name, group));

        // Handle elements
        NamedModelUpdates<JvmElement> jvm = null;
        Collection<PropertyAdd> systemProperties = null;
        NameOffset socketBinding = null;
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case DOMAIN_1_0: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case INTERFACE_SPECS: {
                            parseServerElementInterfaces(name, reader, list);
                            break;
                        }
                        case JVM: {
                            if (jvm != null) {
                                throw new XMLStreamException(element.getLocalName() + " already defined", reader.getLocation());
                            }

                            jvm = parseJvm(reader);
                            list.add(HostServerUpdate.create(name, new ServerElementJvmAdd(jvm.name)));
                            for (AbstractModelUpdate<JvmElement, ?> update : jvm.updates) {
                                list.add(HostServerUpdate.create(name, ServerElementJvmUpdate.create(update)));
                            }
                            break;
                        }
                        case PATHS : {
                            for(PathElementUpdate path : parsePaths(reader, true)) {
                                list.add(HostServerUpdate.create(name, new ServerElementPathAdd(path)));
                            }
                        }
                        case SOCKET_BINDING_GROUP: {
                            if (socketBinding != null) {
                                throw new XMLStreamException(element.getLocalName() + " already defined", reader.getLocation());
                            }
                            socketBinding = parseSocketBindingGroupRef(reader);
                            list.add(HostServerUpdate.create(name, new ServerElementSocketBindingGroupUpdate(socketBinding.name)));
                            if (socketBinding.offset > 0) {
                                list.add(HostServerUpdate.create(name, new ServerElementSocketBindingPortOffsetUpdate(socketBinding.offset)));
                            }
                            break;
                        }
                        case SYSTEM_PROPERTIES: {
                            if (systemProperties != null) {
                                throw new XMLStreamException(element.getLocalName() + " already declared", reader.getLocation());
                            }
                            systemProperties = parseProperties(reader, Element.PROPERTY, true);
                            for(final PropertyAdd propertyUpdate : systemProperties) {
                                list.add(HostServerUpdate.create(name, new ServerElementSystemPropertyUpdate(propertyUpdate)));
                            }
                            break;
                        }
                        default: throw unexpectedElement(reader);
                    }
                    break;
                }
                default: throw unexpectedElement(reader);
            }
        }

        boolean isStart = start == null ? true : start.booleanValue();
        list.add(HostServerUpdate.create(name, new ServerElementStartStopUpdate(isStart)));
    }

    static void parseDomainPaths(final XMLExtendedStreamReader reader, List<? super AbstractDomainModelUpdate<?>> list) throws XMLStreamException {
        for(final PathElementUpdate update : parsePaths(reader, false)) {
            list.add(new DomainPathAdd(update));
        }
    }

    static void parseHostPaths(final XMLExtendedStreamReader reader, List<? super AbstractHostModelUpdate<?>> list) throws XMLStreamException {
        for(final PathElementUpdate update : parsePaths(reader, true)) {
            list.add(new HostPathAdd(update));
        }
    }

    static void parseServerModelPaths(final XMLExtendedStreamReader reader, List<? super AbstractServerModelUpdate<?>> list) throws XMLStreamException {
        for(final PathElementUpdate update : parsePaths(reader, true)) {
            list.add(new ServerPathAdd(update));
        }
    }

    static Collection<PathElementUpdate> parsePaths(final XMLExtendedStreamReader reader, final boolean requirePath) throws XMLStreamException {
        final Set<String> pathNames = new LinkedHashSet<String>();
        final List<PathElementUpdate> updates = new ArrayList<PathElementUpdate>();
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case DOMAIN_1_0: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case PATH: {
                            final PathElementUpdate update = parsePath(reader, requirePath);
                            if(! pathNames.add(update.getName())) {
                                throw new XMLStreamException(update.getName() + " already defined", reader.getLocation());
                            }
                            updates.add(update);
                            break;
                        } default: {
                            throw unexpectedElement(reader);
                        }
                    }
                    break;
                } default: {
                    throw unexpectedElement(reader);
                }
            }
        }
        return updates;
    }

    static PathElementUpdate parsePath(final XMLExtendedStreamReader reader, final boolean requirePath) throws XMLStreamException {
        String name = null;
        String path = null;
        String relativeTo = null;
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i ++) {
            final String value = reader.getAttributeValue(i);
            if (reader.getAttributeNamespace(i) != null) {
                throw unexpectedAttribute(reader, i);
            } else {
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                switch (attribute) {
                    case NAME: {
                        name = value.trim();
                        if(PathElement.RESTRICTED.contains(value)) {
                            throw ParseUtils.invalidAttributeValue(reader, i);
                        }
                        break;
                    } case PATH: {
                        path = value;
                        break;
                    }
                    case RELATIVE_TO: {
                        relativeTo = value;
                        break;
                    }
                    default: {
                        throw unexpectedAttribute(reader, i);
                    }
                }
            }
        }
        if(name == null) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.NAME));
        }
        if(requirePath && path == null) {
            throw ParseUtils.missingRequired(reader, Collections.singleton(Attribute.PATH));
        }
        ParseUtils.requireNoContent(reader);
        return new PathElementUpdate(name, path, relativeTo);
    }

    private static Element nextElement(XMLExtendedStreamReader reader) throws XMLStreamException {
        if (reader.nextTag() == END_ELEMENT) {
            return null;
        }
        if (Namespace.forUri(reader.getNamespaceURI()) != Namespace.DOMAIN_1_0) {
            throw unexpectedElement(reader);
        }
        return Element.forName(reader.getLocalName());
    }

    private static class ExtensionContextImpl implements ExtensionContext {

        private final XMLExtendedStreamReader reader;

        public ExtensionContextImpl(final XMLExtendedStreamReader reader) {
            this.reader = reader;
        }

        public <E extends AbstractSubsystemElement<E>> void registerSubsystem(final String namespaceUri, final XMLElementReader<ParseResult<SubsystemConfiguration<E>>> elementReader) {
            final XMLMapper mapper = reader.getXMLMapper();
            mapper.registerRootElement(new QName(namespaceUri, Element.SUBSYSTEM.getLocalName()), elementReader);
        }
    }

    private static int parsePort(String value, Attribute attribute, XMLExtendedStreamReader reader, boolean allowEphemeral) throws XMLStreamException {
        int legal;
        try {
            legal = Integer.parseInt(value);
            int min = allowEphemeral ? 0 : 1;
            if (legal < min || legal >= 65536) {
                throw new XMLStreamException("Illegal value " + value +
                        " for attribute '" + attribute.getLocalName() +
                        "' must be between " + min + " and 65536", reader.getLocation());
            }
        }
        catch (NumberFormatException nfe) {
            throw new XMLStreamException("Illegal value " + value +
                    " for attribute '" + attribute.getLocalName() +
                    "' must be an integer", reader.getLocation(), nfe);
        }
        return legal;
    }

    static class NamedModelUpdates<E extends AbstractModelElement<E>> {
        final String name;
        final List<AbstractModelUpdate<E, ?>> updates;

        NamedModelUpdates(final String name, List<AbstractModelUpdate<E, ?>> updates) {
            this.name = name;
            this.updates = updates;
        }
    }

    static class NameOffset {
        final String name;
        final int offset;

        NameOffset(String name, int offset) {
            this.name = name;
            this.offset = offset;
        }

    }

}
TOP

Related Classes of org.jboss.as.model.ModelXmlParsers

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.