package org.xnio;
import static javax.xml.stream.XMLStreamConstants.*;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Collections;
import org.wildfly.client.config.ClientConfiguration;
import org.wildfly.client.config.ConfigXMLParseException;
import org.wildfly.client.config.ConfigurationXMLStreamReader;
import org.wildfly.common.net.CidrAddress;
final class XnioXmlParser {
private static final String NS_XNIO_3_5 = "urn:xnio:3.5";
static XnioWorker parseWorker(Xnio xnio) throws ConfigXMLParseException, IOException {
return parseWorker(xnio, ClientConfiguration.getInstance());
}
static XnioWorker parseWorker(Xnio xnio, ClientConfiguration clientConfiguration) throws ConfigXMLParseException, IOException {
final XnioWorker.Builder builder = xnio.createWorkerBuilder();
if (clientConfiguration == null) {
return null;
}
builder.setDaemon(true);
final ConfigurationXMLStreamReader reader = clientConfiguration.readConfiguration(Collections.singleton(NS_XNIO_3_5));
parseDocument(reader, builder);
return builder.build();
}
private static void parseDocument(final ConfigurationXMLStreamReader reader, final XnioWorker.Builder workerBuilder) throws ConfigXMLParseException {
if (reader.hasNext()) switch (reader.nextTag()) {
case START_ELEMENT: {
checkElementNamespace(reader);
switch (reader.getLocalName()) {
case "worker": {
parseWorkerElement(reader, workerBuilder);
break;
}
default: throw reader.unexpectedElement();
}
break;
}
default: {
throw reader.unexpectedContent();
}
}
}
private static void parseWorkerElement(final ConfigurationXMLStreamReader reader, final XnioWorker.Builder workerBuilder) throws ConfigXMLParseException {
requireNoAttributes(reader);
int foundBits = 0;
while (reader.hasNext()) {
switch (reader.nextTag()) {
case END_ELEMENT: {
return;
}
case START_ELEMENT: {
checkElementNamespace(reader);
switch (reader.getLocalName()) {
case "daemon-threads": {
if (isSet(foundBits, 0)) throw reader.unexpectedElement();
foundBits = setBit(foundBits, 0);
parseDaemonThreads(reader, workerBuilder);
break;
}
case "worker-name": {
if (isSet(foundBits, 1)) throw reader.unexpectedElement();
foundBits = setBit(foundBits, 1);
parseWorkerName(reader, workerBuilder);
break;
}
case "pool-size": {
if (isSet(foundBits, 2)) throw reader.unexpectedElement();
foundBits = setBit(foundBits, 2);
parsePoolSize(reader, workerBuilder);
break;
}
case "task-keepalive": {
if (isSet(foundBits, 3)) throw reader.unexpectedElement();
foundBits = setBit(foundBits, 3);
parseTaskKeepalive(reader, workerBuilder);
break;
}
case "io-threads": {
if (isSet(foundBits, 4)) throw reader.unexpectedElement();
foundBits = setBit(foundBits, 4);
parseIoThreads(reader, workerBuilder);
break;
}
case "stack-size": {
if (isSet(foundBits, 5)) throw reader.unexpectedElement();
foundBits = setBit(foundBits, 5);
parseStackSize(reader, workerBuilder);
break;
}
case "outbound-bind-addresses": {
if (isSet(foundBits, 6)) throw reader.unexpectedElement();
foundBits = setBit(foundBits, 6);
parseOutboundBindAddresses(reader, workerBuilder);
break;
}
default: {
throw reader.unexpectedElement();
}
}
}
}
}
throw reader.unexpectedDocumentEnd();
}
private static void parseDaemonThreads(final ConfigurationXMLStreamReader reader, final XnioWorker.Builder workerBuilder) throws ConfigXMLParseException {
requireSingleAttribute(reader, "value");
final boolean daemon = reader.getBooleanAttributeValueResolved(0);
if (! reader.hasNext()) throw reader.unexpectedDocumentEnd();
if (reader.nextTag() != END_ELEMENT) throw reader.unexpectedElement();
workerBuilder.setDaemon(daemon);
return;
}
private static void parseWorkerName(final ConfigurationXMLStreamReader reader, final XnioWorker.Builder workerBuilder) throws ConfigXMLParseException {
requireSingleAttribute(reader, "value");
String name = reader.getAttributeValueResolved(0);
if (! reader.hasNext()) throw reader.unexpectedDocumentEnd();
if (reader.nextTag() != END_ELEMENT) throw reader.unexpectedElement();
workerBuilder.setWorkerName(name);
return;
}
private static void parsePoolSize(final ConfigurationXMLStreamReader reader, final XnioWorker.Builder workerBuilder) throws ConfigXMLParseException {
requireSingleAttribute(reader, "max-threads");
int threadCount = reader.getIntAttributeValueResolved(0);
if (! reader.hasNext()) throw reader.unexpectedDocumentEnd();
if (reader.nextTag() != END_ELEMENT) throw reader.unexpectedElement();
workerBuilder.setCoreWorkerPoolSize(threadCount);
workerBuilder.setMaxWorkerPoolSize(threadCount);
return;
}
private static void parseTaskKeepalive(final ConfigurationXMLStreamReader reader, final XnioWorker.Builder workerBuilder) throws ConfigXMLParseException {
requireSingleAttribute(reader, "value");
int duration = reader.getIntAttributeValueResolved(0);
if (! reader.hasNext()) throw reader.unexpectedDocumentEnd();
if (reader.nextTag() != END_ELEMENT) throw reader.unexpectedElement();
workerBuilder.setWorkerKeepAlive(duration);
return;
}
private static void parseIoThreads(final ConfigurationXMLStreamReader reader, final XnioWorker.Builder workerBuilder) throws ConfigXMLParseException {
requireSingleAttribute(reader, "value");
int threadCount = reader.getIntAttributeValueResolved(0);
if (! reader.hasNext()) throw reader.unexpectedDocumentEnd();
if (reader.nextTag() != END_ELEMENT) throw reader.unexpectedElement();
workerBuilder.setWorkerIoThreads(threadCount);
return;
}
private static void parseStackSize(final ConfigurationXMLStreamReader reader, final XnioWorker.Builder workerBuilder) throws ConfigXMLParseException {
requireSingleAttribute(reader, "value");
long stackSize = reader.getLongAttributeValueResolved(0);
if (! reader.hasNext()) throw reader.unexpectedDocumentEnd();
if (reader.nextTag() != END_ELEMENT) throw reader.unexpectedElement();
workerBuilder.setWorkerStackSize(stackSize);
return;
}
private static void parseOutboundBindAddresses(final ConfigurationXMLStreamReader reader, final XnioWorker.Builder workerBuilder) throws ConfigXMLParseException {
requireNoAttributes(reader);
for (;;) {
if (! reader.hasNext()) throw reader.unexpectedDocumentEnd();
if (reader.nextTag() == START_ELEMENT) {
checkElementNamespace(reader);
if (! reader.getLocalName().equals("bind-address")) {
throw reader.unexpectedElement();
}
parseBindAddress(reader, workerBuilder);
} else {
assert reader.getEventType() == END_ELEMENT;
return;
}
}
}
private static void parseBindAddress(final ConfigurationXMLStreamReader reader, final XnioWorker.Builder workerBuilder) throws ConfigXMLParseException {
final int cnt = reader.getAttributeCount();
InetAddress address = null;
int port = 0;
CidrAddress match = null;
for (int i = 0; i < cnt; i ++) {
checkAttributeNamespace(reader, i);
switch (reader.getAttributeLocalName(i)) {
case "match": {
match = reader.getCidrAddressAttributeValueResolved(i);
break;
}
case "bind-address": {
address = reader.getInetAddressAttributeValueResolved(i);
break;
}
case "bind-port": {
port = reader.getIntAttributeValueResolved(i, 0, 65535);
break;
}
default: {
throw reader.unexpectedAttribute(i);
}
}
}
if (match == null) throw reader.missingRequiredAttribute(null, "match");
if (address == null) throw reader.missingRequiredAttribute(null, "bind-address");
workerBuilder.addBindAddressConfiguration(match, new InetSocketAddress(address, port));
if (! reader.hasNext()) throw reader.unexpectedDocumentEnd();
if (reader.nextTag() != END_ELEMENT) throw reader.unexpectedElement();
}
private static void checkElementNamespace(final ConfigurationXMLStreamReader reader) throws ConfigXMLParseException {
if (! reader.getNamespaceURI().equals(NS_XNIO_3_5)) {
throw reader.unexpectedElement();
}
}
private static void checkAttributeNamespace(final ConfigurationXMLStreamReader reader, final int idx) throws ConfigXMLParseException {
final String attributeNamespace = reader.getAttributeNamespace(idx);
if (attributeNamespace != null && ! attributeNamespace.isEmpty()) {
throw reader.unexpectedAttribute(idx);
}
}
private static void requireNoAttributes(final ConfigurationXMLStreamReader reader) throws ConfigXMLParseException {
final int attributeCount = reader.getAttributeCount();
if (attributeCount > 0) {
throw reader.unexpectedAttribute(0);
}
}
private static void requireSingleAttribute(final ConfigurationXMLStreamReader reader, final String attributeName) throws ConfigXMLParseException {
final int attributeCount = reader.getAttributeCount();
if (attributeCount < 1) {
throw reader.missingRequiredAttribute("", attributeName);
}
checkAttributeNamespace(reader, 0);
if (! reader.getAttributeLocalName(0).equals(attributeName)) {
throw reader.unexpectedAttribute(0);
}
if (attributeCount > 1) {
throw reader.unexpectedAttribute(1);
}
}
private static boolean isSet(int var, int bit) {
return (var & 1 << bit) != 0;
}
private static int setBit(int var, int bit) {
return var | 1 << bit;
}
}