/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, 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.controller.parsing;
import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
import static org.jboss.as.controller.ControllerMessages.MESSAGES;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ANY;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ARCHIVE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.BOOT_TIME;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CLIENT_MAPPINGS;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CORE_SERVICE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEPLOYMENT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DESTINATION_ADDRESS;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DESTINATION_PORT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ENABLED;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FIXED_PORT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FIXED_SOURCE_PORT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HASH;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HOST;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.INTERFACE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.LOCAL_DESTINATION_OUTBOUND_SOCKET_BINDING;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.MULTICAST_ADDRESS;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.MULTICAST_PORT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAME;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAMESPACES;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NOT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PATH;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PORT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RELATIVE_TO;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REMOTE_DESTINATION_OUTBOUND_SOCKET_BINDING;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RUNTIME_NAME;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SCHEMA_LOCATIONS;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOCKET_BINDING;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOCKET_BINDING_GROUP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOCKET_BINDING_PORT_OFFSET;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOCKET_BINDING_REF;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOURCE_INTERFACE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOURCE_NETWORK;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOURCE_PORT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SYSTEM_PROPERTY;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.VALUE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.VAULT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.VAULT_OPTIONS;
import static org.jboss.as.controller.parsing.ParseUtils.duplicateNamedElement;
import static org.jboss.as.controller.parsing.ParseUtils.invalidAttributeValue;
import static org.jboss.as.controller.parsing.ParseUtils.isNoNamespaceAttribute;
import static org.jboss.as.controller.parsing.ParseUtils.missingRequired;
import static org.jboss.as.controller.parsing.ParseUtils.parseBoundedIntegerAttribute;
import static org.jboss.as.controller.parsing.ParseUtils.parsePossibleExpression;
import static org.jboss.as.controller.parsing.ParseUtils.requireAttributes;
import static org.jboss.as.controller.parsing.ParseUtils.requireNamespace;
import static org.jboss.as.controller.parsing.ParseUtils.requireNoAttributes;
import static org.jboss.as.controller.parsing.ParseUtils.requireNoContent;
import static org.jboss.as.controller.parsing.ParseUtils.requireNoNamespaceAttribute;
import static org.jboss.as.controller.parsing.ParseUtils.requireSingleAttribute;
import static org.jboss.as.controller.parsing.ParseUtils.unexpectedAttribute;
import static org.jboss.as.controller.parsing.ParseUtils.unexpectedElement;
import static org.jboss.as.controller.parsing.ParseUtils.unexpectedEndElement;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.xml.stream.Location;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import org.jboss.as.controller.HashUtil;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.operations.common.NamespaceAddHandler;
import org.jboss.as.controller.operations.common.SchemaLocationAddHandler;
import org.jboss.as.controller.operations.common.SystemPropertyAddHandler;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.controller.persistence.ModelMarshallingContext;
import org.jboss.as.controller.resource.SocketBindingGroupResourceDefinition;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import org.jboss.dmr.Property;
import org.jboss.staxmapper.XMLElementReader;
import org.jboss.staxmapper.XMLElementWriter;
import org.jboss.staxmapper.XMLExtendedStreamReader;
import org.jboss.staxmapper.XMLExtendedStreamWriter;
/**
* Bits of parsing and marshalling logic that are common across more than one of standalone.xml, domain.xml and host.xml.
*
* @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
* @author <a href="mailto:darran.lofthouse@jboss.com">Darran Lofthouse</a>
*/
public abstract class CommonXml implements XMLElementReader<List<ModelNode>>, XMLElementWriter<ModelMarshallingContext> {
/** The restricted path names. */
protected static final Set<String> RESTRICTED_PATHS;
static {
final HashSet<String> set = new HashSet<String>(10);
// Define the restricted path names.
set.add("jboss.home");
set.add("jboss.home.dir");
set.add("user.home");
set.add("user.dir");
set.add("java.home");
set.add("jboss.server.base.dir");
set.add("jboss.server.data.dir");
set.add("jboss.server.log.dir");
set.add("jboss.server.temp.dir");
// NOTE we actually don't create services for the following
// however the names remain restricted for use in the configuration
set.add("jboss.modules.dir");
set.add("jboss.server.deploy.dir");
set.add("jboss.domain.servers.dir");
RESTRICTED_PATHS = Collections.unmodifiableSet(set);
}
private static final char[] NEW_LINE = new char[]{'\n'};
protected CommonXml() {
}
protected void parseNamespaces(final XMLExtendedStreamReader reader, final ModelNode address, final List<ModelNode> nodes) {
final int namespaceCount = reader.getNamespaceCount();
for (int i = 0; i < namespaceCount; i++) {
String prefix = reader.getNamespacePrefix(i);
// FIXME - remove once STXM-8 is released
if (prefix != null && prefix.length() > 0) {
nodes.add(NamespaceAddHandler.getAddNamespaceOperation(address, prefix, reader.getNamespaceURI(i)));
}
}
}
protected void readHeadComment(final XMLExtendedStreamReader reader, final ModelNode address, final List<ModelNode> nodes)
throws XMLStreamException {
// TODO STXM-6
}
protected void readTailComment(final XMLExtendedStreamReader reader, final ModelNode address, final List<ModelNode> nodes)
throws XMLStreamException {
// TODO STXM-6
}
protected void parseSchemaLocations(final XMLExtendedStreamReader reader, final ModelNode address,
final List<ModelNode> updateList, final int idx) throws XMLStreamException {
final List<String> elements = reader.getListAttributeValue(idx);
final List<String> values = new ArrayList<String>();
for (String element : elements) {
if (!element.trim().isEmpty()) {
values.add(element);
}
}
if ((values.size() & 1) != 0) {
throw invalidAttributeValue(reader, idx);
}
final Iterator<String> it = values.iterator();
while (it.hasNext()) {
String key = it.next();
String val = it.next();
if (key.length() > 0 && val.length() > 0) {
updateList.add(SchemaLocationAddHandler.getAddSchemaLocationOperation(address, key, val));
}
}
}
protected void writeSchemaLocation(final XMLExtendedStreamWriter writer, final ModelNode modelNode)
throws XMLStreamException {
if (!modelNode.hasDefined(SCHEMA_LOCATIONS)) {
return;
}
final StringBuilder b = new StringBuilder();
final Iterator<ModelNode> iterator = modelNode.get(SCHEMA_LOCATIONS).asList().iterator();
while (iterator.hasNext()) {
final ModelNode location = iterator.next();
final Property property = location.asProperty();
b.append(property.getName()).append(' ').append(property.getValue().asString());
if (iterator.hasNext()) {
b.append(' ');
}
}
if (b.length() > 0) {
writer.writeAttribute(Namespace.XML_SCHEMA_INSTANCE.getUriString(), Attribute.SCHEMA_LOCATION.getLocalName(),
b.toString());
}
}
protected void writeNamespaces(final XMLExtendedStreamWriter writer, final ModelNode modelNode) throws XMLStreamException {
final boolean needXsd = modelNode.hasDefined(SCHEMA_LOCATIONS) && modelNode.get(SCHEMA_LOCATIONS).asInt() > 0;
final boolean hasNamespaces = modelNode.hasDefined(NAMESPACES);
if (!needXsd && !hasNamespaces) {
return;
}
boolean wroteXsd = false;
final String xsdUri = Namespace.XML_SCHEMA_INSTANCE.getUriString();
if (hasNamespaces) {
for (final Property property : modelNode.get(NAMESPACES).asPropertyList()) {
final String uri = property.getValue().asString();
writer.writeNamespace(property.getName(), uri);
if (!wroteXsd && xsdUri.equals(uri)) {
wroteXsd = true;
}
}
}
if (needXsd && !wroteXsd) {
writer.writeNamespace("xsd", xsdUri);
}
}
protected static void writeElement(final XMLExtendedStreamWriter writer, final Element element) throws XMLStreamException {
writer.writeStartElement(element.getLocalName());
}
protected void writePaths(final XMLExtendedStreamWriter writer, final ModelNode node) throws XMLStreamException {
List<Property> paths = node.asPropertyList();
if (paths.size() > 0) {
writer.writeStartElement(Element.PATHS.getLocalName());
for (final Property path : paths) {
final ModelNode value = path.getValue();
writer.writeEmptyElement(Element.PATH.getLocalName());
writer.writeAttribute(Attribute.NAME.getLocalName(), path.getName());
writer.writeAttribute(Attribute.PATH.getLocalName(), value.get(PATH).asString());
if (value.has(RELATIVE_TO) && value.get(RELATIVE_TO).isDefined()) {
writer.writeAttribute(Attribute.RELATIVE_TO.getLocalName(), value.get(RELATIVE_TO).asString());
}
}
writer.writeEndElement();
}
}
protected void parseFSBaseType(final XMLExtendedStreamReader reader, final ModelNode parent, final boolean isArchive)
throws XMLStreamException {
final ModelNode content = parent.get("content").add();
content.get(ARCHIVE).set(isArchive);
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
if (!isNoNamespaceAttribute(reader, i)) {
throw unexpectedAttribute(reader, i);
}
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
final String value = reader.getAttributeValue(i);
switch (attribute) {
case PATH:
content.get(PATH).set(value);
break;
case RELATIVE_TO:
content.get(RELATIVE_TO).set(value);
break;
default:
throw unexpectedAttribute(reader, i);
}
}
// Handle elements
requireNoContent(reader);
}
protected void parsePaths(final XMLExtendedStreamReader reader, final ModelNode address, final Namespace expectedNs, final List<ModelNode> list,
final boolean requirePath) throws XMLStreamException {
final Set<String> pathNames = new HashSet<String>();
while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
final Element element = Element.forName(reader.getLocalName());
requireNamespace(reader, expectedNs);
switch (element) {
case PATH: {
parsePath(reader, address, list, requirePath, pathNames);
break;
}
default: {
throw unexpectedElement(reader);
}
}
}
}
protected void parsePath(final XMLExtendedStreamReader reader, final ModelNode address, final List<ModelNode> list,
final boolean requirePath, final Set<String> defined) 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 (!isNoNamespaceAttribute(reader, i)) {
throw unexpectedAttribute(reader, i);
} else {
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
switch (attribute) {
case NAME: {
name = value.trim();
if (RESTRICTED_PATHS.contains(value)) {
throw MESSAGES.reserved(name, reader.getLocation());
}
if (!defined.add(name)) {
throw MESSAGES.alreadyDefined(name, reader.getLocation());
}
break;
}
case PATH: {
path = value;
break;
}
case RELATIVE_TO: {
relativeTo = value;
break;
}
default: {
throw unexpectedAttribute(reader, i);
}
}
}
}
if (name == null) {
throw missingRequired(reader, Collections.singleton(Attribute.NAME));
}
if (requirePath && path == null) {
throw missingRequired(reader, Collections.singleton(Attribute.PATH));
}
requireNoContent(reader);
final ModelNode update = new ModelNode();
update.get(OP_ADDR).set(address).add(ModelDescriptionConstants.PATH, name);
update.get(OP).set(ADD);
update.get(NAME).set(name);
if (path != null)
update.get(PATH).set(path);
if (relativeTo != null)
update.get(RELATIVE_TO).set(relativeTo);
list.add(update);
}
protected void parseSystemProperties(final XMLExtendedStreamReader reader, final ModelNode address, final Namespace expectedNs,
final List<ModelNode> updates, boolean standalone) throws XMLStreamException {
while (reader.nextTag() != END_ELEMENT) {
requireNamespace(reader, expectedNs);
final Element element = Element.forName(reader.getLocalName());
if (element != Element.PROPERTY) {
throw unexpectedElement(reader);
}
String name = null;
String value = null;
Boolean boottime = null;
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
final String val = reader.getAttributeValue(i);
if (!isNoNamespaceAttribute(reader, i)) {
throw unexpectedAttribute(reader, i);
} else {
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
switch (attribute) {
case NAME: {
if (name != null) {
throw ParseUtils.duplicateAttribute(reader, NAME);
}
name = val;
break;
}
case VALUE: {
if (value != null) {
throw ParseUtils.duplicateAttribute(reader, VALUE);
}
value = val;
break;
}
case BOOT_TIME: {
if (standalone) {
throw unexpectedAttribute(reader, i);
}
boottime = Boolean.valueOf(val);
break;
}
default: {
throw unexpectedAttribute(reader, i);
}
}
}
}
requireNoContent(reader);
ModelNode propAddr = new ModelNode().set(address).add(SYSTEM_PROPERTY, name);
ModelNode op = Util.getEmptyOperation(SystemPropertyAddHandler.OPERATION_NAME, propAddr);
op.get(VALUE).set(value);
if (boottime != null) {
op.get(BOOT_TIME).set(boottime.booleanValue());
}
updates.add(op);
}
}
public static ModelNode parseProperties(final XMLExtendedStreamReader reader, final Namespace expectedNs) throws XMLStreamException {
final ModelNode properties = new ModelNode();
while (reader.nextTag() != END_ELEMENT) {
requireNamespace(reader, expectedNs);
if (Element.forName(reader.getLocalName()) != Element.PROPERTY) {
throw unexpectedElement(reader);
}
final String[] array = requireAttributes(reader, Attribute.NAME.getLocalName(), Attribute.VALUE.getLocalName());
requireNoContent(reader);
properties.get(array[0]).set(array[1]);
}
return properties;
}
protected void parseInterfaceCriteria(final XMLExtendedStreamReader reader, final Namespace expectedNs, final ModelNode interfaceModel)
throws XMLStreamException {
// all subsequent elements are criteria elements
if (reader.nextTag() == END_ELEMENT) {
return;
}
requireNamespace(reader, expectedNs);
Element element = Element.forName(reader.getLocalName());
switch (element) {
case ANY_ADDRESS:
case ANY_IPV4_ADDRESS:
case ANY_IPV6_ADDRESS: {
interfaceModel.get(element.getLocalName()).set(true);
requireNoContent(reader); // consume this element
requireNoContent(reader); // consume rest of criteria (no further content allowed)
return;
}
}
do {
requireNamespace(reader, expectedNs);
element = Element.forName(reader.getLocalName());
switch (element) {
case ANY:
parseCompoundInterfaceCriterion(reader, expectedNs, interfaceModel.get(ANY).setEmptyObject());
break;
case NOT:
parseCompoundInterfaceCriterion(reader, expectedNs, interfaceModel.get(NOT).setEmptyObject());
break;
default: {
// parseSimpleInterfaceCriterion(reader, criteria.add().set(element.getLocalName(), new
// ModelNode()).get(element.getLocalName()));
parseSimpleInterfaceCriterion(reader, interfaceModel, false);
break;
}
}
} while (reader.nextTag() != END_ELEMENT);
}
protected void parseCompoundInterfaceCriterion(final XMLExtendedStreamReader reader, final Namespace expectedNs, final ModelNode subModel)
throws XMLStreamException {
requireNoAttributes(reader);
while (reader.nextTag() != END_ELEMENT) {
requireNamespace(reader, expectedNs);
parseSimpleInterfaceCriterion(reader, subModel, true);
}
}
protected void parseContentType(final XMLExtendedStreamReader reader, final ModelNode parent) throws XMLStreamException {
final ModelNode content = parent.get("content").add();
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
if (!isNoNamespaceAttribute(reader, i)) {
throw unexpectedAttribute(reader, i);
}
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
final String value = reader.getAttributeValue(i);
switch (attribute) {
case SHA1:
try {
content.get(HASH).set(HashUtil.hexStringToByteArray(value));
} catch (final Exception e) {
throw MESSAGES.invalidSha1Value(e, value, attribute.getLocalName(), reader.getLocation());
}
break;
default:
throw unexpectedAttribute(reader, i);
}
}
// Handle elements
requireNoContent(reader);
}
/**
* Creates the appropriate AbstractInterfaceCriteriaElement for simple criterion.
*
* Note! changes/additions made here will likely need to be added to the corresponding write method that handles the write
* of the element. Failure to do so will result in a configuration that can be read, but not written out.
*
* @see {@link #writeInterfaceCriteria(org.jboss.staxmapper.XMLExtendedStreamWriter, org.jboss.dmr.ModelNode, boolean)}
* @throws javax.xml.stream.XMLStreamException if an error occurs
*/
protected void parseSimpleInterfaceCriterion(final XMLExtendedStreamReader reader, final ModelNode subModel, boolean nested)
throws XMLStreamException {
final Element element = Element.forName(reader.getLocalName());
final String localName = element.getLocalName();
switch (element) {
case INET_ADDRESS: {
requireSingleAttribute(reader, Attribute.VALUE.getLocalName());
final String value = reader.getAttributeValue(0);
ModelNode valueNode = parsePossibleExpression(value);
requireNoContent(reader);
// todo: validate IP address
if(nested) {
subModel.get(localName).add(valueNode);
} else {
subModel.get(localName).set(valueNode);
}
break;
}
case LOOPBACK_ADDRESS: {
requireSingleAttribute(reader, Attribute.VALUE.getLocalName());
final String value = reader.getAttributeValue(0);
ModelNode valueNode = parsePossibleExpression(value);
requireNoContent(reader);
// todo: validate IP address
subModel.get(localName).set(valueNode);
break;
}
case LINK_LOCAL_ADDRESS:
case LOOPBACK:
case MULTICAST:
case POINT_TO_POINT:
case PUBLIC_ADDRESS:
case SITE_LOCAL_ADDRESS:
case UP:
case VIRTUAL: {
requireNoAttributes(reader);
requireNoContent(reader);
subModel.get(localName).set(true);
break;
}
case NIC: {
requireSingleAttribute(reader, Attribute.NAME.getLocalName());
final String value = reader.getAttributeValue(0);
requireNoContent(reader);
// todo: validate NIC name
if(nested) {
subModel.get(localName).add(value);
} else {
subModel.get(localName).set(value);
}
break;
}
case NIC_MATCH: {
requireSingleAttribute(reader, Attribute.PATTERN.getLocalName());
final String value = reader.getAttributeValue(0);
requireNoContent(reader);
// todo: validate pattern
if(nested) {
subModel.get(localName).add(value);
} else {
subModel.get(localName).set(value);
}
break;
}
case SUBNET_MATCH: {
requireSingleAttribute(reader, Attribute.VALUE.getLocalName());
final String value = reader.getAttributeValue(0);
requireNoContent(reader);
validateAddressMask(value, reader.getLocation());
if(nested) {
subModel.get(localName).add(value);
} else {
subModel.get(localName).set(value);
}
break;
}
default:
throw unexpectedElement(reader);
}
}
private void validateAddressMask(String value, Location location) throws XMLStreamException {
final String[] split = value.split("/");
try {
if (split.length != 2) {
throw new XMLStreamException(MESSAGES.invalidAddressMaskValue(value), location);
}
// todo - possible DNS hit here
final InetAddress addr = InetAddress.getByName(split[0]);
// Validate both parts of the split
addr.getAddress();
Integer.parseInt(split[1]);
} catch (final NumberFormatException e) {
throw new XMLStreamException(MESSAGES.invalidAddressMask(split[1], e.getLocalizedMessage()),
location, e);
} catch (final UnknownHostException e) {
throw new XMLStreamException(MESSAGES.invalidAddressValue(split[0], e.getLocalizedMessage()),
location, e);
}
}
protected void parseInterfaces(final XMLExtendedStreamReader reader, final Set<String> names, final ModelNode address,
final Namespace expectedNs, final List<ModelNode> list, final boolean checkSpecified) throws XMLStreamException {
requireNoAttributes(reader);
while (reader.nextTag() != END_ELEMENT) {
requireNamespace(reader, expectedNs);
Element element = Element.forName(reader.getLocalName());
if (Element.INTERFACE != element) {
throw unexpectedElement(reader);
}
// Attributes
requireSingleAttribute(reader, Attribute.NAME.getLocalName());
final String name = reader.getAttributeValue(0);
if (!names.add(name)) {
throw MESSAGES.duplicateInterfaceDeclaration(reader.getLocation());
}
final ModelNode interfaceAdd = new ModelNode();
interfaceAdd.get(OP_ADDR).set(address).add(ModelDescriptionConstants.INTERFACE, name);
interfaceAdd.get(OP).set(ADD);
final ModelNode criteriaNode = interfaceAdd;
parseInterfaceCriteria(reader, expectedNs, interfaceAdd);
if (checkSpecified && criteriaNode.getType() != ModelType.STRING && criteriaNode.getType() != ModelType.EXPRESSION
&& criteriaNode.asInt() == 0) {
throw unexpectedEndElement(reader);
}
list.add(interfaceAdd);
}
}
protected void parseSocketBindingGroupRef(final XMLExtendedStreamReader reader, final ModelNode address,
final List<ModelNode> updates) 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 (!isNoNamespaceAttribute(reader, i)) {
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 MESSAGES.invalidValueGreaterThan(attribute.getLocalName(), offset, 0, reader.getLocation());
}
} catch (final NumberFormatException e) {
throw MESSAGES.invalid(e, offset, attribute.getLocalName(), reader.getLocation());
}
break;
}
default:
throw unexpectedAttribute(reader, i);
}
}
}
if (name == null) {
throw missingRequired(reader, Collections.singleton(Attribute.REF));
}
// Handle elements
requireNoContent(reader);
ModelNode update = Util.getWriteAttributeOperation(address, SOCKET_BINDING_GROUP, name);
updates.add(update);
if (offset < 0) {
offset = 0;
}
if (offset > 0) {
update = Util.getWriteAttributeOperation(address, SOCKET_BINDING_PORT_OFFSET, offset);
}
updates.add(update);
}
protected String parseSocketBinding(final XMLExtendedStreamReader reader, final Set<String> interfaces,
final ModelNode address, final List<ModelNode> updates) throws XMLStreamException {
final EnumSet<Attribute> required = EnumSet.of(Attribute.NAME, Attribute.PORT);
String name = null;
final ModelNode binding = new ModelNode();
binding.get(OP_ADDR); // undefined until we parse name
binding.get(OP).set(ADD);
// Handle attributes
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
final String value = reader.getAttributeValue(i);
if (!isNoNamespaceAttribute(reader, i)) {
throw unexpectedAttribute(reader, i);
} else {
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
required.remove(attribute);
switch (attribute) {
case NAME: {
name = value;
binding.get(OP_ADDR).set(address).add(SOCKET_BINDING, name);
break;
}
case INTERFACE: {
if (!interfaces.contains(value)) {
throw MESSAGES.unknownInterface(value, attribute.getLocalName(),
Element.INTERFACES.getLocalName(), reader.getLocation());
}
binding.get(INTERFACE).set(value);
break;
}
case PORT: {
binding.get(PORT).set(parseBoundedIntegerAttribute(reader, i, 0, 65535, true));
break;
}
case FIXED_PORT: {
binding.get(FIXED_PORT).set(Boolean.parseBoolean(value));
break;
}
case MULTICAST_ADDRESS: {
ModelNode mcastNode = parsePossibleExpression(value);
if (mcastNode.getType() == ModelType.EXPRESSION) {
binding.get(MULTICAST_ADDRESS).set(mcastNode);
} else {
try {
final InetAddress mcastAddr = InetAddress.getByName(value);
if (!mcastAddr.isMulticastAddress()) {
throw MESSAGES.invalidMulticastAddress(value, attribute.getLocalName(), reader.getLocation());
}
binding.get(MULTICAST_ADDRESS).set(value);
} catch (final UnknownHostException e) {
throw MESSAGES.invalidMulticastAddress(e, value, attribute.getLocalName(), reader.getLocation());
}
}
break;
}
case MULTICAST_PORT: {
binding.get(MULTICAST_PORT).set(parseBoundedIntegerAttribute(reader, i, 1, 65535, true));
break;
}
default:
throw unexpectedAttribute(reader, i);
}
}
}
if (!required.isEmpty()) {
throw missingRequired(reader, required);
}
// Handle elements
// Handle elements
while (reader.nextTag() != END_ELEMENT) {
final Element element = Element.forName(reader.getLocalName());
switch (element) {
case CLIENT_MAPPING:
binding.get(CLIENT_MAPPINGS).add(parseClientMapping(reader));
break;
default:
throw unexpectedElement(reader);
}
}
updates.add(binding);
return name;
}
private ModelNode parseClientMapping(XMLExtendedStreamReader reader) throws XMLStreamException {
final ModelNode mapping = new ModelNode();
// Ensure all fields exist, even if not defined
final ModelNode sourceNetwork = mapping.get(SOURCE_NETWORK);
final ModelNode destination = mapping.get(DESTINATION_ADDRESS);
final ModelNode destinationPort = mapping.get(DESTINATION_PORT);
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
final String value = reader.getAttributeValue(i);
if (!isNoNamespaceAttribute(reader, i)) {
throw unexpectedAttribute(reader, i);
}
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
switch (attribute) {
case SOURCE_NETWORK:
validateAddressMask(value, reader.getLocation());
sourceNetwork.set(value);
break;
case DESTINATION_ADDRESS:
if (value == null || value.isEmpty()) {
throw invalidAttributeValue(reader, i);
}
// We can't validate the address since the client is allowed to resolve private DNS names
destination.set(value);
break;
case DESTINATION_PORT: {
destinationPort.set(parseBoundedIntegerAttribute(reader, i, 0, 65535, true));
break;
}
}
}
if (!destination.isDefined()) {
throw MESSAGES.missingRequiredAttributes(new StringBuilder(DESTINATION_ADDRESS), reader.getLocation());
}
requireNoContent(reader);
return mapping;
}
protected String parseOutboundSocketBinding(final XMLExtendedStreamReader reader, final Set<String> interfaces,
final String socketBindingGroupName, final ModelNode address, final List<ModelNode> updates) throws XMLStreamException {
final EnumSet<Attribute> required = EnumSet.of(Attribute.NAME);
String outboundSocketBindingName = null;
final ModelNode outboundSocketBindingAddOperation = new ModelNode();
outboundSocketBindingAddOperation.get(OP).set(ADD); // address for this ADD operation will be set later, once the local-destination or remote-destination is parsed
// Handle attributes
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
final String value = reader.getAttributeValue(i);
if (!isNoNamespaceAttribute(reader, i)) {
throw unexpectedAttribute(reader, i);
} else {
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
required.remove(attribute);
switch (attribute) {
case NAME: {
outboundSocketBindingName = value;
break;
}
case SOURCE_INTERFACE: {
if (!interfaces.contains(value)) {
throw MESSAGES.unknownValueForElement(Attribute.SOURCE_INTERFACE.getLocalName(), value,
Element.INTERFACE.getLocalName(), Element.INTERFACES.getLocalName(), reader.getLocation());
}
outboundSocketBindingAddOperation.get(SOURCE_INTERFACE).set(value);
break;
}
case SOURCE_PORT: {
outboundSocketBindingAddOperation.get(SOURCE_PORT).set(parseBoundedIntegerAttribute(reader, i, 0, 65535, true));
break;
}
case FIXED_SOURCE_PORT: {
outboundSocketBindingAddOperation.get(FIXED_SOURCE_PORT).set(parsePossibleExpression(value));
break;
}
default:
throw unexpectedAttribute(reader, i);
}
}
}
if (!required.isEmpty()) {
throw missingRequired(reader, required);
}
// Handle elements
boolean mutuallyExclusiveElementAlreadyFound = false;
while (reader.hasNext() && reader.nextTag() != XMLStreamConstants.END_ELEMENT) {
switch (Element.forName(reader.getLocalName())) {
case LOCAL_DESTINATION: {
if (mutuallyExclusiveElementAlreadyFound) {
throw MESSAGES.invalidOutboundSocketBinding(outboundSocketBindingName, Element.LOCAL_DESTINATION.getLocalName(),
Element.REMOTE_DESTINATION.getLocalName(), reader.getLocation());
} else {
mutuallyExclusiveElementAlreadyFound = true;
}
// parse the local destination outbound socket binding
this.parseLocalDestinationOutboundSocketBinding(reader, outboundSocketBindingName, outboundSocketBindingAddOperation);
// set the address of the add operation
// /socket-binding-group=<groupname>/local-destination-outbound-socket-binding=<outboundSocketBindingName>
final ModelNode addr = address.clone().add(LOCAL_DESTINATION_OUTBOUND_SOCKET_BINDING, outboundSocketBindingName);
outboundSocketBindingAddOperation.get(OP_ADDR).set(addr);
break;
}
case REMOTE_DESTINATION: {
if (mutuallyExclusiveElementAlreadyFound) {
throw MESSAGES.invalidOutboundSocketBinding(outboundSocketBindingName, Element.LOCAL_DESTINATION.getLocalName(),
Element.REMOTE_DESTINATION.getLocalName(), reader.getLocation());
} else {
mutuallyExclusiveElementAlreadyFound = true;
}
// parse the remote destination outbound socket binding
this.parseRemoteDestinationOutboundSocketBinding(reader, outboundSocketBindingName, outboundSocketBindingAddOperation);
// /socket-binding-group=<groupname>/remote-destination-outbound-socket-binding=<outboundSocketBindingName>
final ModelNode addr = address.clone().add(REMOTE_DESTINATION_OUTBOUND_SOCKET_BINDING, outboundSocketBindingName);
outboundSocketBindingAddOperation.get(OP_ADDR).set(addr);
break;
}
default: {
throw unexpectedElement(reader);
}
}
}
// add the "add" operations to the updates
updates.add(outboundSocketBindingAddOperation);
return outboundSocketBindingName;
}
private void parseLocalDestinationOutboundSocketBinding(final XMLExtendedStreamReader reader, final String outboundSocketBindingName,
final ModelNode outboundSocketBindingAddOperation) throws XMLStreamException {
final EnumSet<Attribute> required = EnumSet.of(Attribute.SOCKET_BINDING_REF);
// Handle attributes
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
final String value = reader.getAttributeValue(i);
if (!isNoNamespaceAttribute(reader, i)) {
throw unexpectedAttribute(reader, i);
} else {
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
required.remove(attribute);
switch (attribute) {
case SOCKET_BINDING_REF: {
outboundSocketBindingAddOperation.get(SOCKET_BINDING_REF).set(value);
break;
}
default:
throw unexpectedAttribute(reader, i);
}
}
}
if (!required.isEmpty()) {
throw missingRequired(reader, required);
}
// Handle elements
requireNoContent(reader);
}
private void parseRemoteDestinationOutboundSocketBinding(final XMLExtendedStreamReader reader, final String outboundSocketBindingName,
final ModelNode outboundSocketBindingAddOperation) throws XMLStreamException {
final EnumSet<Attribute> required = EnumSet.of(Attribute.HOST, Attribute.PORT);
// Handle attributes
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
final String value = reader.getAttributeValue(i);
if (!isNoNamespaceAttribute(reader, i)) {
throw unexpectedAttribute(reader, i);
} else {
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
required.remove(attribute);
switch (attribute) {
case HOST: {
outboundSocketBindingAddOperation.get(HOST).set(value);
break;
}
case PORT: {
outboundSocketBindingAddOperation.get(PORT).set(parseBoundedIntegerAttribute(reader, i, 0, 65535, true));
break;
}
default:
throw unexpectedAttribute(reader, i);
}
}
}
if (!required.isEmpty()) {
throw missingRequired(reader, required);
}
// Handle elements
requireNoContent(reader);
}
protected void parseDeployments(final XMLExtendedStreamReader reader, final ModelNode address, final Namespace expectedNs, final List<ModelNode> list,
final boolean allowEnabled) throws XMLStreamException {
requireNoAttributes(reader);
final Set<String> names = new HashSet<String>();
while (reader.nextTag() != END_ELEMENT) {
requireNamespace(reader, expectedNs);
Element deployment = Element.forName(reader.getLocalName());
if (Element.DEPLOYMENT != deployment) {
throw unexpectedElement(reader);
}
// Handle attributes
String uniqueName = null;
String runtimeName = null;
String startInput = null;
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
final String value = reader.getAttributeValue(i);
if (!isNoNamespaceAttribute(reader, i)) {
throw unexpectedAttribute(reader, i);
} else {
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
switch (attribute) {
case NAME: {
if (!names.add(value)) {
throw duplicateNamedElement(reader, value);
}
uniqueName = value;
break;
}
case RUNTIME_NAME: {
runtimeName = value;
break;
}
case ENABLED: {
if (allowEnabled) {
startInput = value;
break;
} else {
throw unexpectedAttribute(reader, i);
}
}
default:
throw unexpectedAttribute(reader, i);
}
}
}
if (uniqueName == null) {
throw missingRequired(reader, Collections.singleton(Attribute.NAME));
}
if (runtimeName == null) {
throw missingRequired(reader, Collections.singleton(Attribute.RUNTIME_NAME));
}
final boolean enabled = startInput == null ? true : Boolean.parseBoolean(startInput);
final ModelNode deploymentAddress = address.clone().add(DEPLOYMENT, uniqueName);
final ModelNode deploymentAdd = Util.getEmptyOperation(ADD, deploymentAddress);
// Handle elements
while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
requireNamespace(reader, expectedNs);
final Element element = Element.forName(reader.getLocalName());
switch (element) {
case CONTENT:
parseContentType(reader, deploymentAdd);
break;
case FS_ARCHIVE:
parseFSBaseType(reader, deploymentAdd, true);
break;
case FS_EXPLODED:
parseFSBaseType(reader, deploymentAdd, false);
break;
default:
throw unexpectedElement(reader);
}
}
deploymentAdd.get(RUNTIME_NAME).set(runtimeName);
if (allowEnabled) {
deploymentAdd.get(ENABLED).set(enabled);
}
list.add(deploymentAdd);
}
}
protected void parseVault(final XMLExtendedStreamReader reader, final ModelNode address, final Namespace expectedNs, final List<ModelNode> list) throws XMLStreamException {
// Some form of assertion could be added to ensure we did not reach here for 1.0 schema based XML but in reality that
// should not happen.
final int vaultAttribCount = reader.getAttributeCount();
ModelNode vault = new ModelNode();
String code = null;
if(vaultAttribCount > 1) {
throw unexpectedAttribute(reader, vaultAttribCount);
}
for (int i = 0; i < vaultAttribCount; i++) {
requireNoNamespaceAttribute(reader, i);
final String value = reader.getAttributeValue(i);
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
switch (attribute) {
case CODE: {
code = value;
vault.get(Attribute.CODE.getLocalName()).set(code);
break;
}
default:
throw unexpectedAttribute(reader, i);
}
}
ModelNode vaultAddress = address.clone();
vaultAddress.add(CORE_SERVICE, VAULT);
if(code != null){
vault.get(Attribute.CODE.getLocalName()).set(code);
}
vault.get(OP_ADDR).set(vaultAddress);
vault.get(OP).set(ADD);
while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
requireNamespace(reader, expectedNs);
final Element element = Element.forName(reader.getLocalName());
switch (element) {
case VAULT_OPTION: {
parseModuleOption(reader, vault.get(VAULT_OPTIONS));
break;
}
}
}
list.add(vault);
}
protected void parseModuleOption(XMLExtendedStreamReader reader, ModelNode moduleOptions) throws XMLStreamException {
String name = null;
String val = null;
EnumSet<Attribute> required = EnumSet.of(Attribute.NAME, Attribute.VALUE);
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
requireNoNamespaceAttribute(reader, i);
final String value = reader.getAttributeValue(i);
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
required.remove(attribute);
switch (attribute) {
case NAME: {
name = value;
break;
}
case VALUE: {
val = value;
break;
}
default:
throw unexpectedAttribute(reader, i);
}
}
if (required.size() > 0) {
throw missingRequired(reader, required);
}
moduleOptions.add(name, val);
requireNoContent(reader);
}
/**
* Write the interfaces including the criteria elements.
*
* @param writer the xml stream writer
* @param modelNode the model
* @throws XMLStreamException
*/
protected void writeInterfaces(final XMLExtendedStreamWriter writer, final ModelNode modelNode) throws XMLStreamException {
writer.writeStartElement(Element.INTERFACES.getLocalName());
final Set<String> interfaces = modelNode.keys();
for (String ifaceName : interfaces) {
final ModelNode iface = modelNode.get(ifaceName);
writer.writeStartElement(Element.INTERFACE.getLocalName());
writeAttribute(writer, Attribute.NAME, ifaceName);
// <any-* /> is just handled at the root
if(iface.get(Element.ANY_ADDRESS.getLocalName()).asBoolean(false)) {
writer.writeEmptyElement(Element.ANY_ADDRESS.getLocalName());
} else if(iface.get(Element.ANY_IPV4_ADDRESS.getLocalName()).asBoolean(false)) {
writer.writeEmptyElement(Element.ANY_IPV4_ADDRESS.getLocalName());
} else if(iface.get(Element.ANY_IPV6_ADDRESS.getLocalName()).asBoolean(false)) {
writer.writeEmptyElement(Element.ANY_IPV6_ADDRESS.getLocalName());
} else {
// Write the other criteria elements
writeInterfaceCriteria(writer, iface, false);
}
writer.writeEndElement();
}
writer.writeEndElement();
}
/**
* Write the criteria elements, extracting the information of the sub-model.
*
* @param writer the xml stream writer
* @param subModel the interface model
* @param nested whether it the criteria elements are nested as part of <not /> or <any />
* @throws XMLStreamException
*/
private void writeInterfaceCriteria(final XMLExtendedStreamWriter writer, final ModelNode subModel, final boolean nested) throws XMLStreamException {
for(final Property property : subModel.asPropertyList()) {
if(property.getValue().isDefined()) {
writeInterfaceCriteria(writer, property, nested);
}
}
}
private void writeInterfaceCriteria(final XMLExtendedStreamWriter writer, final Property property, final boolean nested) throws XMLStreamException {
final Element element = Element.forName(property.getName());
switch (element) {
case INET_ADDRESS:
writeInterfaceCriteria(writer, element, Attribute.VALUE, property.getValue(), nested);
break;
case LOOPBACK_ADDRESS:
writeInterfaceCriteria(writer, element, Attribute.VALUE, property.getValue(), false);
break;
case LINK_LOCAL_ADDRESS:
case LOOPBACK:
case MULTICAST:
case POINT_TO_POINT:
case PUBLIC_ADDRESS:
case SITE_LOCAL_ADDRESS:
case UP:
case VIRTUAL: {
if(property.getValue().asBoolean(false)) {
writer.writeEmptyElement(element.getLocalName());
}
break;
}
case NIC:
writeInterfaceCriteria(writer, element, Attribute.NAME, property.getValue(), nested);
break;
case NIC_MATCH:
writeInterfaceCriteria(writer, element, Attribute.PATTERN, property.getValue(), nested);
break;
case SUBNET_MATCH:
writeInterfaceCriteria(writer, element, Attribute.VALUE, property.getValue(), nested);
break;
case ANY :
case NOT:
if(nested) {
break;
}
writer.writeStartElement(element.getLocalName());
writeInterfaceCriteria(writer, property.getValue(), true);
writer.writeEndElement();
break;
case NAME:
// not a criteria element; ignore
break;
default: {
// TODO we perhaps should just log a warning.
throw MESSAGES.unknownCriteriaInterfaceProperty(property.getName());
}
}
}
private static void writeInterfaceCriteria(final XMLExtendedStreamWriter writer, final Element element, final Attribute attribute, final ModelNode subModel, boolean asList) throws XMLStreamException {
if(asList) {
// Nested criteria elements are represented as list in the model
writeListAsMultipleElements(writer, element, attribute, subModel);
} else {
writeSingleElement(writer, element, attribute, subModel);
}
}
private static void writeSingleElement(final XMLExtendedStreamWriter writer, final Element element, final Attribute attribute, final ModelNode subModel) throws XMLStreamException {
writer.writeEmptyElement(element.getLocalName());
writeAttribute(writer, attribute, subModel.asString());
}
private static void writeListAsMultipleElements(final XMLExtendedStreamWriter writer, final Element element, Attribute attribute, final ModelNode subModel) throws XMLStreamException {
final List<ModelNode> list = subModel.asList();
for(final ModelNode node : list) {
writer.writeEmptyElement(element.getLocalName());
writeAttribute(writer, attribute, node.asString());
}
}
protected void writeSocketBindingGroup(XMLExtendedStreamWriter writer, ModelNode bindingGroup, boolean fromServer)
throws XMLStreamException {
writer.writeStartElement(Element.SOCKET_BINDING_GROUP.getLocalName());
SocketBindingGroupResourceDefinition.NAME.marshallAsAttribute(bindingGroup, writer);
SocketBindingGroupResourceDefinition.DEFAULT_INTERFACE.marshallAsAttribute(bindingGroup, writer);
if (fromServer) {
SocketBindingGroupResourceDefinition.PORT_OFFSET.marshallAsAttribute(bindingGroup, writer);
}
if (!fromServer) {
SocketBindingGroupResourceDefinition.INCLUDES.marshallAsElement(bindingGroup, writer);
}
if (bindingGroup.hasDefined(SOCKET_BINDING)) {
ModelNode bindings = bindingGroup.get(SOCKET_BINDING);
for (String bindingName : bindings.keys()) {
ModelNode binding = bindings.get(bindingName);
writer.writeStartElement(Element.SOCKET_BINDING.getLocalName());
writeAttribute(writer, Attribute.NAME, bindingName);
ModelNode attr = binding.get(INTERFACE);
if (attr.isDefined()) {
writeAttribute(writer, Attribute.INTERFACE, attr.asString());
}
attr = binding.get(PORT);
writeAttribute(writer, Attribute.PORT, attr.asString());
attr = binding.get(FIXED_PORT);
if (attr.isDefined() && attr.asBoolean()) {
writeAttribute(writer, Attribute.FIXED_PORT, attr.asString());
}
attr = binding.get(MULTICAST_ADDRESS);
if (attr.isDefined()) {
writeAttribute(writer, Attribute.MULTICAST_ADDRESS, attr.asString());
}
attr = binding.get(MULTICAST_PORT);
if (attr.isDefined()) {
writeAttribute(writer, Attribute.MULTICAST_PORT, attr.asString());
}
attr = binding.get(CLIENT_MAPPINGS);
if (attr.isDefined()) {
for (ModelNode mapping : attr.asList()) {
writer.writeEmptyElement(Element.CLIENT_MAPPING.getLocalName());
attr = mapping.get(SOURCE_NETWORK);
if (attr.isDefined()) {
writeAttribute(writer, Attribute.SOURCE_NETWORK, attr.asString());
}
attr = mapping.get(DESTINATION_ADDRESS);
if (attr.isDefined()) {
writeAttribute(writer, Attribute.DESTINATION_ADDRESS, attr.asString());
}
attr = mapping.get(DESTINATION_PORT);
if (attr.isDefined()) {
writeAttribute(writer, Attribute.DESTINATION_PORT, attr.asString());
}
}
}
writer.writeEndElement();
}
}
// outbound-socket-binding (for local destination)
if (bindingGroup.hasDefined(LOCAL_DESTINATION_OUTBOUND_SOCKET_BINDING)) {
final ModelNode localDestinationOutboundSocketBindings = bindingGroup.get(LOCAL_DESTINATION_OUTBOUND_SOCKET_BINDING);
for (final String outboundSocketBindingName : localDestinationOutboundSocketBindings.keys()) {
final ModelNode outboundSocketBinding = localDestinationOutboundSocketBindings.get(outboundSocketBindingName);
// <outbound-socket-binding>
writer.writeStartElement(Element.OUTBOUND_SOCKET_BINDING.getLocalName());
// name of the outbound socket binding
writeAttribute(writer, Attribute.NAME, outboundSocketBindingName);
// (optional) source port
if (outboundSocketBinding.hasDefined(SOURCE_PORT)) {
final String sourcePort = outboundSocketBinding.get(SOURCE_PORT).asString();
writeAttribute(writer, Attribute.SOURCE_PORT, sourcePort);
}
// (optional) source interface
if (outboundSocketBinding.hasDefined(SOURCE_INTERFACE)) {
final String sourceInterface = outboundSocketBinding.get(SOURCE_INTERFACE).asString();
writeAttribute(writer, Attribute.SOURCE_INTERFACE, sourceInterface);
}
// (optional) fixedSourcePort
if (outboundSocketBinding.hasDefined(FIXED_SOURCE_PORT)) {
final String fixedSourcePort = outboundSocketBinding.get(FIXED_SOURCE_PORT).asString();
writeAttribute(writer, Attribute.FIXED_SOURCE_PORT, fixedSourcePort);
}
// write the <local-destination> element
writer.writeStartElement(Element.LOCAL_DESTINATION.getLocalName());
// socket-binding-ref
final ModelNode socketBindingRef = outboundSocketBinding.get(SOCKET_BINDING_REF);
// write the socket-binding-ref attribute for the local-destination element
writeAttribute(writer, Attribute.SOCKET_BINDING_REF, socketBindingRef.asString());
// </local-destination>
writer.writeEndElement();
// </outbound-socket-binding>
writer.writeEndElement();
}
}
// outbound-socket-binding (for remote destination)
if (bindingGroup.hasDefined(REMOTE_DESTINATION_OUTBOUND_SOCKET_BINDING)) {
final ModelNode remoteDestinationOutboundSocketBindings = bindingGroup.get(REMOTE_DESTINATION_OUTBOUND_SOCKET_BINDING);
for (final String outboundSocketBindingName : remoteDestinationOutboundSocketBindings.keys()) {
final ModelNode outboundSocketBinding = remoteDestinationOutboundSocketBindings.get(outboundSocketBindingName);
// <outbound-socket-binding>
writer.writeStartElement(Element.OUTBOUND_SOCKET_BINDING.getLocalName());
// name of the outbound socket binding
writeAttribute(writer, Attribute.NAME, outboundSocketBindingName);
// (optional) source port
if (outboundSocketBinding.hasDefined(SOURCE_PORT)) {
final String sourcePort = outboundSocketBinding.get(SOURCE_PORT).asString();
writeAttribute(writer, Attribute.SOURCE_PORT, sourcePort);
}
// (optional) source interface
if (outboundSocketBinding.hasDefined(SOURCE_INTERFACE)) {
final String sourceInterface = outboundSocketBinding.get(SOURCE_INTERFACE).asString();
writeAttribute(writer, Attribute.SOURCE_INTERFACE, sourceInterface);
}
// (optional) fixedSourcePort
if (outboundSocketBinding.hasDefined(FIXED_SOURCE_PORT)) {
final String fixedSourcePort = outboundSocketBinding.get(FIXED_SOURCE_PORT).asString();
writeAttribute(writer, Attribute.FIXED_SOURCE_PORT, fixedSourcePort);
}
// write the <remote-destination> element
writer.writeStartElement(Element.REMOTE_DESTINATION.getLocalName());
// destination host
final ModelNode host = outboundSocketBinding.get(HOST);
writeAttribute(writer, Attribute.HOST, host.asString());
// destination port
final ModelNode destPort = outboundSocketBinding.get(PORT);
writeAttribute(writer, Attribute.PORT, destPort.asString());
// </remote-destination>
writer.writeEndElement();
// </outbound-socket-binding>
writer.writeEndElement();
}
}
// </socket-binding-group>
writer.writeEndElement();
}
protected void writeProperties(final XMLExtendedStreamWriter writer, final ModelNode modelNode, Element element,
boolean standalone) throws XMLStreamException {
final List<Property> properties = modelNode.asPropertyList();
if (properties.size() > 0) {
writer.writeStartElement(element.getLocalName());
for (Property prop : properties) {
writer.writeStartElement(Element.PROPERTY.getLocalName());
writeAttribute(writer, Attribute.NAME, prop.getName());
ModelNode sysProp = prop.getValue();
if (sysProp.hasDefined(VALUE)) {
writeAttribute(writer, Attribute.VALUE, sysProp.get(VALUE).asString());
}
if (!standalone && sysProp.hasDefined(BOOT_TIME) && !sysProp.get(BOOT_TIME).asBoolean()) {
writeAttribute(writer, Attribute.BOOT_TIME, "false");
}
writer.writeEndElement();
}
writer.writeEndElement();
}
}
protected static void writeAttribute(XMLExtendedStreamWriter writer, Attribute attribute, String value)
throws XMLStreamException {
writer.writeAttribute(attribute.getLocalName(), value);
}
protected static void writeContentItem(final XMLExtendedStreamWriter writer, final ModelNode contentItem)
throws XMLStreamException {
if (contentItem.has(HASH)) {
writeElement(writer, Element.CONTENT);
writeAttribute(writer, Attribute.SHA1, HashUtil.bytesToHexString(contentItem.require(HASH).asBytes()));
writer.writeEndElement();
} else {
if (contentItem.require(ARCHIVE).asBoolean()) {
writeElement(writer, Element.FS_ARCHIVE);
} else {
writeElement(writer, Element.FS_EXPLODED);
}
writeAttribute(writer, Attribute.PATH, contentItem.require(PATH).asString());
if (contentItem.has(RELATIVE_TO))
writeAttribute(writer, Attribute.RELATIVE_TO, contentItem.require(RELATIVE_TO).asString());
writer.writeEndElement();
}
}
protected void writeVault(XMLExtendedStreamWriter writer, ModelNode vault) throws XMLStreamException {
writer.writeStartElement(Element.VAULT.getLocalName());
String code = vault.hasDefined(Attribute.CODE.getLocalName()) ? vault.get(Attribute.CODE.getLocalName()).asString() : null;
if (code != null && !code.isEmpty()) {
writer.writeAttribute(Attribute.CODE.getLocalName(), code);
}
if (vault.hasDefined(VAULT_OPTIONS)) {
ModelNode properties = vault.get(VAULT_OPTIONS);
for (Property prop : properties.asPropertyList()) {
writer.writeEmptyElement(Element.VAULT_OPTION.getLocalName());
writer.writeAttribute(Attribute.NAME.getLocalName(), prop.getName());
writer.writeAttribute(Attribute.VALUE.getLocalName(), prop.getValue().asString());
}
}
writer.writeEndElement();
}
protected static void writeNewLine(XMLExtendedStreamWriter writer) throws XMLStreamException {
writer.writeCharacters(NEW_LINE, 0, 1);
}
}