/*
* 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 <domain>} 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 <host>} 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 <server>} 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;
}
}
}