/* * 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.threads; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD; 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.SUBSYSTEM; import static org.jboss.as.controller.parsing.ParseUtils.invalidAttributeValue; import static org.jboss.as.controller.parsing.ParseUtils.missingRequired; import static org.jboss.as.controller.parsing.ParseUtils.missingRequiredElement; import static org.jboss.as.controller.parsing.ParseUtils.readStringAttributeElement; import static org.jboss.as.controller.parsing.ParseUtils.requireNoNamespaceAttribute; import static org.jboss.as.controller.parsing.ParseUtils.unexpectedAttribute; import static org.jboss.as.controller.parsing.ParseUtils.unexpectedElement; import static org.jboss.as.threads.CommonAttributes.BLOCKING_BOUNDED_QUEUE_THREAD_POOL; import static org.jboss.as.threads.CommonAttributes.BLOCKING_QUEUELESS_THREAD_POOL; import static org.jboss.as.threads.CommonAttributes.BOUNDED_QUEUE_THREAD_POOL; import static org.jboss.as.threads.CommonAttributes.HANDOFF_EXECUTOR; import static org.jboss.as.threads.CommonAttributes.QUEUELESS_THREAD_POOL; import static org.jboss.as.threads.CommonAttributes.SCHEDULED_THREAD_POOL; import static org.jboss.as.threads.CommonAttributes.THREAD_FACTORY; import static org.jboss.as.threads.CommonAttributes.TIME; import static org.jboss.as.threads.CommonAttributes.UNBOUNDED_QUEUE_THREAD_POOL; import static org.jboss.as.threads.CommonAttributes.UNIT; import java.math.BigDecimal; import java.math.MathContext; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import org.jboss.as.controller.AttributeDefinition; import org.jboss.as.controller.parsing.ParseUtils; import org.jboss.as.controller.persistence.SubsystemMarshallingContext; import org.jboss.dmr.ModelNode; 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; import org.wildfly.common.cpu.ProcessorInfo; /** * Parser for the threads subsystem or for other subsystems that use pieces of the basic threads subsystem * xsd and resource structure. */ public final class ThreadsParser implements XMLStreamConstants, XMLElementReader<List<ModelNode>>,XMLElementWriter<SubsystemMarshallingContext> { static final ThreadsParser INSTANCE = new ThreadsParser(); private static final String SUBSYSTEM_NAME = "threads"; public static ThreadsParser getInstance() { return INSTANCE; } @Override public void readElement(final XMLExtendedStreamReader reader, final List<ModelNode> list) throws XMLStreamException { if (Element.forName(reader.getLocalName()) != Element.SUBSYSTEM) { throw unexpectedElement(reader); } final ModelNode address = new ModelNode(); address.add(SUBSYSTEM, SUBSYSTEM_NAME); address.protect(); final ModelNode subsystem = new ModelNode(); subsystem.get(OP).set(ADD); subsystem.get(OP_ADDR).set(address); list.add(subsystem); String readerNS = reader.getNamespaceURI(); Namespace threadsNamespace = Namespace.forUri(readerNS); switch (threadsNamespace) { case THREADS_1_0: readElement1_0(reader, list, address); break; default: readElement1_1(reader, list, address, readerNS, threadsNamespace); break; } } private void readElement1_0(final XMLExtendedStreamReader reader, final List<ModelNode> list, final ModelNode subsystemAddress) throws XMLStreamException { Namespace threadsNamespace = Namespace.THREADS_1_0; String readerNS = threadsNamespace.getUriString(); while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { Element element = nextElement(reader, readerNS); switch (element) { case BOUNDED_QUEUE_THREAD_POOL: { parseUnknownBoundedQueueThreadPool1_0(reader, readerNS, subsystemAddress, list); break; } case THREAD_FACTORY: { parseThreadFactory(reader, readerNS, threadsNamespace, subsystemAddress, list, THREAD_FACTORY, null); break; } case QUEUELESS_THREAD_POOL: { parseUnknownQueuelessThreadPool1_0(reader, readerNS, subsystemAddress, list); break; } case SCHEDULED_THREAD_POOL: { parseScheduledThreadPool(reader, readerNS, threadsNamespace, subsystemAddress, list, SCHEDULED_THREAD_POOL, null); break; } case UNBOUNDED_QUEUE_THREAD_POOL: { parseUnboundedQueueThreadPool(reader, readerNS, threadsNamespace, subsystemAddress, list, UNBOUNDED_QUEUE_THREAD_POOL, null); break; } default: { throw unexpectedElement(reader); } } } } private void readElement1_1(final XMLExtendedStreamReader reader, final List<ModelNode> list, final ModelNode subsystemAddress, final String readerNS, final Namespace threadsNamespace) throws XMLStreamException { while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { Element element = nextElement(reader, readerNS); switch (element) { case BLOCKING_BOUNDED_QUEUE_THREAD_POOL: { parseBoundedQueueThreadPool1_1(reader, readerNS, threadsNamespace, subsystemAddress, list, BLOCKING_BOUNDED_QUEUE_THREAD_POOL, null, true); break; } case BLOCKING_QUEUELESS_THREAD_POOL: { parseQueuelessThreadPool1_1(reader, readerNS, threadsNamespace, subsystemAddress, list, BLOCKING_QUEUELESS_THREAD_POOL, null, true); break; } case BOUNDED_QUEUE_THREAD_POOL: { parseBoundedQueueThreadPool1_1(reader, readerNS, threadsNamespace, subsystemAddress, list, BOUNDED_QUEUE_THREAD_POOL, null, false); break; } case THREAD_FACTORY: { parseThreadFactory(reader, readerNS, threadsNamespace, subsystemAddress, list, THREAD_FACTORY, null); break; } case QUEUELESS_THREAD_POOL: { parseQueuelessThreadPool1_1(reader, readerNS, threadsNamespace, subsystemAddress, list, QUEUELESS_THREAD_POOL, null, false); break; } case SCHEDULED_THREAD_POOL: { parseScheduledThreadPool(reader, readerNS, threadsNamespace, subsystemAddress, list, SCHEDULED_THREAD_POOL, null); break; } case UNBOUNDED_QUEUE_THREAD_POOL: { parseUnboundedQueueThreadPool(reader, readerNS, threadsNamespace, subsystemAddress, list, UNBOUNDED_QUEUE_THREAD_POOL, null); break; } default: { throw unexpectedElement(reader); } } } } public String parseThreadFactory(final XMLExtendedStreamReader reader, final String expectedNs, Namespace threadsNamespace, final ModelNode parentAddress, final List<ModelNode> list, final String childType, final String providedName) throws XMLStreamException { final ModelNode op = new ModelNode(); list.add(op); op.get(OP).set(ADD); String name = null; 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)); switch (attribute) { case NAME: { name = value; break; } case GROUP_NAME: { PoolAttributeDefinitions.GROUP_NAME.parseAndSetParameter(value, op, reader); break; } case THREAD_NAME_PATTERN: { PoolAttributeDefinitions.THREAD_NAME_PATTERN.parseAndSetParameter(value, op, reader); break; } case PRIORITY: { PoolAttributeDefinitions.PRIORITY.parseAndSetParameter(value, op, reader); break; } default: throw unexpectedAttribute(reader, i); } } if (providedName != null) { name = providedName; } else if (name == null) { throw missingRequired(reader, Collections.singleton(Attribute.NAME)); } final ModelNode address = parentAddress.clone(); address.add(childType, name); address.protect(); op.get(OP_ADDR).set(address); while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { Element element = nextElement(reader, expectedNs); switch (element) { case PROPERTIES: { parseProperties(reader, threadsNamespace); break; } default: { throw unexpectedElement(reader); } } } return name; } public String parseBlockingBoundedQueueThreadPool(final XMLExtendedStreamReader reader, final String expectedNs, final Namespace threadsNamespace, final ModelNode parentAddress, final List<ModelNode> list, final String childType, final String providedName) throws XMLStreamException { switch (threadsNamespace) { case THREADS_1_0: return parseBoundedQueueThreadPool1_0(reader, expectedNs, threadsNamespace, parentAddress, list, childType, providedName, true); default: return parseBoundedQueueThreadPool1_1(reader, expectedNs, threadsNamespace, parentAddress, list, childType, providedName, true); } } public String parseBoundedQueueThreadPool(final XMLExtendedStreamReader reader, final String expectedNs, final Namespace threadsNamespace, final ModelNode parentAddress, final List<ModelNode> list, final String childType, final String providedName) throws XMLStreamException { switch (threadsNamespace) { case THREADS_1_0: return parseBoundedQueueThreadPool1_0(reader, expectedNs, threadsNamespace, parentAddress, list, childType, providedName, false); default: return parseBoundedQueueThreadPool1_1(reader, expectedNs, threadsNamespace, parentAddress, list, childType, providedName, false); } } private void parseUnknownBoundedQueueThreadPool1_0(final XMLExtendedStreamReader reader, final String expectedNs, final ModelNode parentAddress, final List<ModelNode> list) throws XMLStreamException { int count = reader.getAttributeCount(); for (int i = 0; i < count; i++) { requireNoNamespaceAttribute(reader, i); final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i)); switch (attribute) { case BLOCKING: { parseBoundedQueueThreadPool1_0(reader, expectedNs, Namespace.THREADS_1_0, parentAddress, list, BLOCKING_BOUNDED_QUEUE_THREAD_POOL, null, true); return; } default: break; } } parseBoundedQueueThreadPool1_0(reader, expectedNs, Namespace.THREADS_1_0, parentAddress, list, BOUNDED_QUEUE_THREAD_POOL, null, false); } private String parseBoundedQueueThreadPool1_0(final XMLExtendedStreamReader reader, final String expectedNs, final Namespace threadsNamespace, final ModelNode parentAddress, final List<ModelNode> list, final String childType, final String providedName, final boolean blocking) throws XMLStreamException { final ModelNode op = new ModelNode(); list.add(op); op.get(OP).set(ADD); String name = null; 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)); switch (attribute) { case NAME: { name = value; break; } case BLOCKING: { // we ignore this break; } case ALLOW_CORE_TIMEOUT: { PoolAttributeDefinitions.ALLOW_CORE_TIMEOUT.parseAndSetParameter(value, op, reader); break; } default: throw unexpectedAttribute(reader, i); } } if (providedName != null) { name = providedName; } else if (name == null) { throw missingRequired(reader, Collections.singleton(Attribute.NAME)); } final ModelNode address = parentAddress.clone(); address.add(childType, name); address.protect(); op.get(OP_ADDR).set(address); Set<Element> required = EnumSet.of(Element.MAX_THREADS, Element.QUEUE_LENGTH); while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { Element element = nextElement(reader, expectedNs); required.remove(element); switch (element) { case CORE_THREADS: { String scaledCount = parseCount(reader, threadsNamespace); PoolAttributeDefinitions.CORE_THREADS.parseAndSetParameter(scaledCount, op, reader); break; } case HANDOFF_EXECUTOR: { String ref = readStringAttributeElement(reader, Attribute.NAME.getLocalName()); if (!blocking) { PoolAttributeDefinitions.HANDOFF_EXECUTOR.parseAndSetParameter(ref, op, reader); } // else we ignore TODO log a WARN break; } case MAX_THREADS: { String scaledCount = parseCount(reader, threadsNamespace); PoolAttributeDefinitions.MAX_THREADS.parseAndSetParameter(scaledCount, op, reader); break; } case KEEPALIVE_TIME: { PoolAttributeDefinitions.KEEPALIVE_TIME.parseAndSetParameter(op,reader); break; } case THREAD_FACTORY: { String ref = readStringAttributeElement(reader, Attribute.NAME.getLocalName()); PoolAttributeDefinitions.THREAD_FACTORY.parseAndSetParameter(ref, op, reader); break; } case PROPERTIES: { parseProperties(reader, threadsNamespace); break; } case QUEUE_LENGTH: { String scaledCount = parseCount(reader, threadsNamespace); PoolAttributeDefinitions.QUEUE_LENGTH.parseAndSetParameter(scaledCount, op, reader); break; } default: { throw unexpectedElement(reader); } } } if (!required.isEmpty()) { throw missingRequiredElement(reader, required); } return name; } private String parseBoundedQueueThreadPool1_1(final XMLExtendedStreamReader reader, final String expectedNs, final Namespace threadsNamespace, final ModelNode parentAddress, final List<ModelNode> list, final String childType, final String providedName, final boolean blocking) throws XMLStreamException { final ModelNode op = new ModelNode(); list.add(op); op.get(OP).set(ADD); String name = null; 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)); switch (attribute) { case NAME: { name = value; break; } case ALLOW_CORE_TIMEOUT: { PoolAttributeDefinitions.ALLOW_CORE_TIMEOUT.parseAndSetParameter(value, op, reader); break; } default: throw unexpectedAttribute(reader, i); } } if (providedName != null) { name = providedName; } else if (name == null) { throw missingRequired(reader, Collections.singleton(Attribute.NAME)); } final ModelNode address = parentAddress.clone(); address.add(childType, name); address.protect(); op.get(OP_ADDR).set(address); Set<Element> required = EnumSet.of(Element.MAX_THREADS, Element.QUEUE_LENGTH); while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { Element element = nextElement(reader, expectedNs); required.remove(element); switch (element) { case CORE_THREADS: { String scaledCount = parseCount(reader, threadsNamespace); PoolAttributeDefinitions.CORE_THREADS.parseAndSetParameter(scaledCount, op, reader); break; } case HANDOFF_EXECUTOR: { if (blocking) { throw unexpectedElement(reader); } String ref = readStringAttributeElement(reader, Attribute.NAME.getLocalName()); PoolAttributeDefinitions.HANDOFF_EXECUTOR.parseAndSetParameter(ref, op, reader); break; } case MAX_THREADS: { String scaledCount = parseCount(reader, threadsNamespace); PoolAttributeDefinitions.MAX_THREADS.parseAndSetParameter(scaledCount, op, reader); break; } case KEEPALIVE_TIME: { PoolAttributeDefinitions.KEEPALIVE_TIME.parseAndSetParameter(op,reader); break; } case THREAD_FACTORY: { String ref = readStringAttributeElement(reader, Attribute.NAME.getLocalName()); PoolAttributeDefinitions.THREAD_FACTORY.parseAndSetParameter(ref, op, reader); break; } case QUEUE_LENGTH: { String scaledCount = parseCount(reader, threadsNamespace); PoolAttributeDefinitions.QUEUE_LENGTH.parseAndSetParameter(scaledCount, op, reader); break; } default: { throw unexpectedElement(reader); } } } if (!required.isEmpty()) { throw missingRequiredElement(reader, required); } return name; } public String parseUnboundedQueueThreadPool(final XMLExtendedStreamReader reader, String expectedNs, Namespace threadsNamespace, final ModelNode parentAddress, final List<ModelNode> list, final String childType, final String providedName) throws XMLStreamException { final ModelNode op = new ModelNode(); list.add(op); op.get(OP).set(ADD); String name = null; 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)); switch (attribute) { case NAME: { name = value; break; } default: throw unexpectedAttribute(reader, i); } } if (providedName != null) { name = providedName; } else if (name == null) { throw missingRequired(reader, Collections.singleton(Attribute.NAME)); } final ModelNode address = parentAddress.clone(); address.add(childType, name); address.protect(); op.get(OP_ADDR).set(address); boolean foundMaxThreads = false; while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { Element element = nextElement(reader, expectedNs); switch (element) { case MAX_THREADS: { String scaledCount = parseCount(reader, threadsNamespace); PoolAttributeDefinitions.MAX_THREADS.parseAndSetParameter(scaledCount, op, reader); foundMaxThreads = true; break; } case KEEPALIVE_TIME: { PoolAttributeDefinitions.KEEPALIVE_TIME.parseAndSetParameter(op, reader); break; } case THREAD_FACTORY: { String ref = readStringAttributeElement(reader, Attribute.NAME.getLocalName()); PoolAttributeDefinitions.THREAD_FACTORY.parseAndSetParameter(ref, op, reader); break; } case PROPERTIES: { parseProperties(reader, threadsNamespace); break; } default: { throw unexpectedElement(reader); } } } if (!foundMaxThreads) { throw missingRequiredElement(reader, Collections.singleton(Element.MAX_THREADS)); } return name; } public String parseScheduledThreadPool(final XMLExtendedStreamReader reader, String expectedNs, Namespace threadsNamespace, final ModelNode parentAddress, final List<ModelNode> list, final String childType, final String providedName) throws XMLStreamException { final ModelNode op = new ModelNode(); list.add(op); op.get(OP).set(ADD); String name = null; 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)); switch (attribute) { case NAME: { name = value; break; } default: throw unexpectedAttribute(reader, i); } } if (providedName != null) { name = providedName; } else if (name == null) { throw missingRequired(reader, Collections.singleton(Attribute.NAME)); } final ModelNode address = parentAddress.clone(); address.add(childType, name); address.protect(); op.get(OP_ADDR).set(address); boolean foundMaxThreads = false; while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { Element element = nextElement(reader, expectedNs); switch (element) { case MAX_THREADS: { String scaledCount = parseCount(reader, threadsNamespace); PoolAttributeDefinitions.MAX_THREADS.parseAndSetParameter(scaledCount, op, reader); foundMaxThreads = true; break; } case KEEPALIVE_TIME: { PoolAttributeDefinitions.KEEPALIVE_TIME.parseAndSetParameter(op,reader); break; } case THREAD_FACTORY: { String ref = readStringAttributeElement(reader, Attribute.NAME.getLocalName()); PoolAttributeDefinitions.THREAD_FACTORY.parseAndSetParameter(ref, op, reader); break; } case PROPERTIES: { parseProperties(reader, threadsNamespace); break; } default: { throw unexpectedElement(reader); } } } if (!foundMaxThreads) { throw missingRequiredElement(reader, Collections.singleton(Element.MAX_THREADS)); } return name; } private void parseUnknownQueuelessThreadPool1_0(XMLExtendedStreamReader reader, String readerNS, ModelNode subsystemAddress, List<ModelNode> list) throws XMLStreamException { int count = reader.getAttributeCount(); for (int i = 0; i < count; i++) { requireNoNamespaceAttribute(reader, i); final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i)); switch (attribute) { case BLOCKING: { parseQueuelessThreadPool1_0(reader, readerNS, Namespace.THREADS_1_0, subsystemAddress, list, BLOCKING_QUEUELESS_THREAD_POOL, null, true); return; } default: break; } } parseQueuelessThreadPool1_0(reader, readerNS, Namespace.THREADS_1_0, subsystemAddress, list, QUEUELESS_THREAD_POOL, null, false); } private String parseQueuelessThreadPool1_0(final XMLExtendedStreamReader reader, String expectedNs, Namespace threadsNamespace, final ModelNode parentAddress, final List<ModelNode> list, final String childType, final String providedName, final boolean blocking) throws XMLStreamException { final ModelNode op = new ModelNode(); list.add(op); op.get(OP).set(ADD); String name = null; 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)); switch (attribute) { case NAME: { name = value; break; } case BLOCKING: { // ignore break; } default: throw unexpectedAttribute(reader, i); } } if (providedName != null) { name = providedName; } else if (name == null) { throw missingRequired(reader, Collections.singleton(Attribute.NAME)); } final ModelNode address = parentAddress.clone(); address.add(childType, name); address.protect(); op.get(OP_ADDR).set(address); boolean foundMaxThreads = false; while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { Element element = nextElement(reader, expectedNs); switch (element) { case HANDOFF_EXECUTOR: { String ref = readStringAttributeElement(reader, Attribute.NAME.getLocalName()); if (!blocking) { PoolAttributeDefinitions.HANDOFF_EXECUTOR.parseAndSetParameter(ref, op, reader); } break; } case MAX_THREADS: { String scaledCount = parseCount(reader, threadsNamespace); PoolAttributeDefinitions.MAX_THREADS.parseAndSetParameter(scaledCount, op, reader); foundMaxThreads = true; break; } case KEEPALIVE_TIME: { PoolAttributeDefinitions.KEEPALIVE_TIME.parseAndSetParameter(op,reader); break; } case THREAD_FACTORY: { String ref = readStringAttributeElement(reader, Attribute.NAME.getLocalName()); PoolAttributeDefinitions.THREAD_FACTORY.parseAndSetParameter(ref, op, reader); break; } case PROPERTIES: { parseProperties(reader, threadsNamespace); break; } default: { throw unexpectedElement(reader); } } } if (!foundMaxThreads) { throw missingRequiredElement(reader, Collections.singleton(Element.MAX_THREADS)); } return name; } private String parseQueuelessThreadPool1_1(final XMLExtendedStreamReader reader, String expectedNs, Namespace threadsNamespace, final ModelNode parentAddress, final List<ModelNode> list, final String childType, final String providedName, boolean blocking) throws XMLStreamException { final ModelNode op = new ModelNode(); list.add(op); op.get(OP).set(ADD); String name = null; 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)); switch (attribute) { case NAME: { name = value; break; } default: throw unexpectedAttribute(reader, i); } } if (providedName != null) { name = providedName; } else if (name == null) { throw missingRequired(reader, Collections.singleton(Attribute.NAME)); } final ModelNode address = parentAddress.clone(); address.add(childType, name); address.protect(); op.get(OP_ADDR).set(address); boolean foundMaxThreads = false; while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { Element element = nextElement(reader, expectedNs); switch (element) { case HANDOFF_EXECUTOR: { if (blocking) { throw unexpectedElement(reader); } String ref = readStringAttributeElement(reader, Attribute.NAME.getLocalName()); PoolAttributeDefinitions.HANDOFF_EXECUTOR.parseAndSetParameter(ref, op, reader); break; } case MAX_THREADS: { String scaledCount = parseCount(reader, threadsNamespace); PoolAttributeDefinitions.MAX_THREADS.parseAndSetParameter(scaledCount, op, reader); foundMaxThreads = true; break; } case KEEPALIVE_TIME: { PoolAttributeDefinitions.KEEPALIVE_TIME.parseAndSetParameter(op,reader); break; } case THREAD_FACTORY: { String ref = readStringAttributeElement(reader, Attribute.NAME.getLocalName()); PoolAttributeDefinitions.THREAD_FACTORY.parseAndSetParameter(ref, op, reader); break; } default: { throw unexpectedElement(reader); } } } if (!foundMaxThreads) { throw missingRequiredElement(reader, Collections.singleton(Element.MAX_THREADS)); } return name; } private String parseCount(final XMLExtendedStreamReader reader, Namespace expectedNS) throws XMLStreamException { switch (expectedNS) { case THREADS_1_0: return parseScaledCount(reader); default: return readStringAttributeElement(reader, Attribute.COUNT.getLocalName()); } } private String parseScaledCount(final XMLExtendedStreamReader reader) throws XMLStreamException { final int attrCount = reader.getAttributeCount(); BigDecimal count = null; BigDecimal perCpu = new BigDecimal(0); for (int i = 0; i < attrCount; i++) { requireNoNamespaceAttribute(reader, i); final String value = reader.getAttributeValue(i); final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i)); switch (attribute) { case COUNT: { try { count = new BigDecimal(value); if (count.compareTo(BigDecimal.ZERO) < 0) { throw ThreadsLogger.ROOT_LOGGER.countMustBePositive(attribute, reader.getLocation()); } } catch (NumberFormatException e) { throw invalidAttributeValue(reader, i); } break; } case PER_CPU: { try { perCpu = new BigDecimal(value); if (perCpu.compareTo(BigDecimal.ZERO) < 0) { throw ThreadsLogger.ROOT_LOGGER.perCpuMustBePositive(attribute, reader.getLocation()); } } catch (NumberFormatException e) { throw invalidAttributeValue(reader, i); } break; } default: throw unexpectedAttribute(reader, i); } } if (count == null) { throw missingRequired(reader, EnumSet.of(Attribute.COUNT)); } ParseUtils.requireNoContent(reader); int fullCount = getScaledCount(count, perCpu); if (!perCpu.equals(new BigDecimal(0))) { ThreadsLogger.ROOT_LOGGER.perCpuNotSupported(Attribute.PER_CPU, count, Attribute.COUNT, perCpu, Attribute.PER_CPU, ProcessorInfo.availableProcessors(), fullCount, Attribute.COUNT); } return String.valueOf(fullCount); } private static int getScaledCount(BigDecimal count, BigDecimal perCpu) { return count.add(perCpu.multiply(BigDecimal.valueOf((long) ProcessorInfo.availableProcessors()), MathContext.DECIMAL64), MathContext.DECIMAL64).round(MathContext.DECIMAL64).intValueExact(); } private void parseProperties(final XMLExtendedStreamReader reader, final Namespace threadsNamespace) throws XMLStreamException { if (threadsNamespace != Namespace.THREADS_1_0) { throw unexpectedElement(reader); } // else consume and discard the never implemented 1.0 "properties" element. // This code validates, which is a debatable given the data is going to be discarded while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { switch (Element.forName(reader.getLocalName())) { case PROPERTY: { final int attrCount = reader.getAttributeCount(); String propName = null; String propValue = null; for (int i = 0; i < attrCount; i++) { requireNoNamespaceAttribute(reader, i); final String value = reader.getAttributeValue(i); final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i)); switch (attribute) { case NAME: { propName = value; break; } case VALUE: { propValue = value; } break; default: throw unexpectedAttribute(reader, i); } } if (propName == null || propValue == null) { Set<Attribute> missing = new HashSet<Attribute>(); if (propName == null) { missing.add(Attribute.NAME); } if (propValue == null) { missing.add(Attribute.VALUE); } throw missingRequired(reader, missing); } ParseUtils.requireNoContent(reader); } } } } /** * A variation of nextElement that verifies the nextElement is not in a different namespace. * * @param reader the XmlExtendedReader to read from. * @param expectedNamespace the namespace expected. * @return the element or null if the end is reached * @throws XMLStreamException if the namespace is wrong or there is a problem accessing the reader */ private static Element nextElement(XMLExtendedStreamReader reader, String expectedNamespace) throws XMLStreamException { Element element = Element.forName(reader.getLocalName()); if (element == null) { return element; } else if (expectedNamespace.equals(reader.getNamespaceURI())) { return element; } throw unexpectedElement(reader); } /** * {@inheritDoc} */ @Override public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException { context.startSubsystemElement(Namespace.CURRENT.getUriString(), false); ModelNode node = context.getModelNode(); writeThreadsElement(writer, node); writer.writeEndElement(); } public void writeThreadsElement(final XMLExtendedStreamWriter writer, ModelNode node) throws XMLStreamException { if (node.hasDefined(THREAD_FACTORY)) { for (Property property : node.get(THREAD_FACTORY).asPropertyList()) { writeThreadFactory(writer, property); } } if (node.hasDefined(UNBOUNDED_QUEUE_THREAD_POOL)) { for (Property property : node.get(UNBOUNDED_QUEUE_THREAD_POOL).asPropertyList()) { writeUnboundedQueueThreadPool(writer, property); } } if (node.hasDefined(BOUNDED_QUEUE_THREAD_POOL)) { for (Property property : node.get(BOUNDED_QUEUE_THREAD_POOL).asPropertyList()) { writeBoundedQueueThreadPool(writer, property); } } if (node.hasDefined(BLOCKING_BOUNDED_QUEUE_THREAD_POOL)) { for (Property property : node.get(BLOCKING_BOUNDED_QUEUE_THREAD_POOL).asPropertyList()) { writeBlockingBoundedQueueThreadPool(writer, property); } } if (node.hasDefined(QUEUELESS_THREAD_POOL)) { for (Property property : node.get(QUEUELESS_THREAD_POOL).asPropertyList()) { writeQueuelessThreadPool(writer, property); } } if (node.hasDefined(BLOCKING_QUEUELESS_THREAD_POOL)) { for (Property property : node.get(BLOCKING_QUEUELESS_THREAD_POOL).asPropertyList()) { writeBlockingQueuelessThreadPool(writer, property); } } if (node.hasDefined(SCHEDULED_THREAD_POOL)) { for (Property property : node.get(SCHEDULED_THREAD_POOL).asPropertyList()) { writeScheduledQueueThreadPool(writer, property); } } } public void writeThreadFactory(final XMLExtendedStreamWriter writer, final Property property) throws XMLStreamException { writeThreadFactory(writer, property, Element.THREAD_FACTORY.getLocalName(), true); } public void writeThreadFactory(final XMLExtendedStreamWriter writer, final Property property, final String elementName, final boolean includeName) throws XMLStreamException { writer.writeStartElement(elementName); ModelNode node = property.getValue(); if (includeName) { writer.writeAttribute(Attribute.NAME.getLocalName(), property.getName()); } PoolAttributeDefinitions.GROUP_NAME.marshallAsAttribute(node, writer); PoolAttributeDefinitions.THREAD_NAME_PATTERN.marshallAsAttribute(node, writer); PoolAttributeDefinitions.PRIORITY.marshallAsAttribute(node, writer); writer.writeEndElement(); } public void writeBlockingBoundedQueueThreadPool(final XMLExtendedStreamWriter writer, final Property property) throws XMLStreamException { writeBoundedQueueThreadPool(writer, property, Element.BLOCKING_BOUNDED_QUEUE_THREAD_POOL.getLocalName(), true, true); } public void writeBoundedQueueThreadPool(final XMLExtendedStreamWriter writer, final Property property) throws XMLStreamException { writeBoundedQueueThreadPool(writer, property, Element.BOUNDED_QUEUE_THREAD_POOL.getLocalName(), true, false); } public void writeBoundedQueueThreadPool(final XMLExtendedStreamWriter writer, final Property property, final String elementName, final boolean includeName) throws XMLStreamException { writeBoundedQueueThreadPool(writer, property, elementName, includeName, false); } public void writeBoundedQueueThreadPool(final XMLExtendedStreamWriter writer, final Property property, final String elementName, final boolean includeName, final boolean blocking) throws XMLStreamException { writer.writeStartElement(elementName); ModelNode node = property.getValue(); if (includeName) { writer.writeAttribute(Attribute.NAME.getLocalName(), property.getName()); } PoolAttributeDefinitions.ALLOW_CORE_TIMEOUT.marshallAsAttribute(node, writer); writeCountElement(PoolAttributeDefinitions.CORE_THREADS, node, writer); writeCountElement(PoolAttributeDefinitions.QUEUE_LENGTH, node, writer); writeCountElement(PoolAttributeDefinitions.MAX_THREADS, node, writer); writeTime(writer, node, Element.KEEPALIVE_TIME); writeRef(writer, node, Element.THREAD_FACTORY, THREAD_FACTORY); if (!blocking) { writeRef(writer, node, Element.HANDOFF_EXECUTOR, HANDOFF_EXECUTOR); } writer.writeEndElement(); } private void writeCountElement(AttributeDefinition attributeDefinition, ModelNode model, XMLExtendedStreamWriter writer) throws XMLStreamException { if (attributeDefinition.isMarshallable(model)) { writer.writeEmptyElement(attributeDefinition.getXmlName()); writer.writeAttribute(Attribute.COUNT.getLocalName(), model.get(attributeDefinition.getName()).asString()); } } public void writeBlockingQueuelessThreadPool(final XMLExtendedStreamWriter writer, final Property property) throws XMLStreamException { writeQueuelessThreadPool(writer, property, Element.BLOCKING_QUEUELESS_THREAD_POOL.getLocalName(), true, true); } public void writeQueuelessThreadPool(final XMLExtendedStreamWriter writer, final Property property) throws XMLStreamException { writeQueuelessThreadPool(writer, property, Element.QUEUELESS_THREAD_POOL.getLocalName(), true, false); } private void writeQueuelessThreadPool(final XMLExtendedStreamWriter writer, final Property property, final String elementName, final boolean includeName, final boolean blocking) throws XMLStreamException { writer.writeStartElement(elementName); ModelNode node = property.getValue(); if (includeName) { writer.writeAttribute(Attribute.NAME.getLocalName(), property.getName()); } writeCountElement(PoolAttributeDefinitions.MAX_THREADS, node, writer); writeTime(writer, node, Element.KEEPALIVE_TIME); writeRef(writer, node, Element.THREAD_FACTORY, THREAD_FACTORY); if (!blocking) { writeRef(writer, node, Element.HANDOFF_EXECUTOR, HANDOFF_EXECUTOR); } writer.writeEndElement(); } public void writeScheduledQueueThreadPool(final XMLExtendedStreamWriter writer, final Property property) throws XMLStreamException { writeScheduledQueueThreadPool(writer, property, Element.SCHEDULED_THREAD_POOL.getLocalName(), true); } public void writeScheduledQueueThreadPool(final XMLExtendedStreamWriter writer, final Property property, final String elementName, final boolean includeName) throws XMLStreamException { writer.writeStartElement(elementName); ModelNode node = property.getValue(); if (includeName) { writer.writeAttribute(Attribute.NAME.getLocalName(), property.getName()); } writeCountElement(PoolAttributeDefinitions.MAX_THREADS, node, writer); writeTime(writer, node, Element.KEEPALIVE_TIME); writeRef(writer, node, Element.THREAD_FACTORY, THREAD_FACTORY); writer.writeEndElement(); } public void writeUnboundedQueueThreadPool(final XMLExtendedStreamWriter writer, final Property property) throws XMLStreamException { writeUnboundedQueueThreadPool(writer, property, Element.UNBOUNDED_QUEUE_THREAD_POOL.getLocalName(), true); } public void writeUnboundedQueueThreadPool(final XMLExtendedStreamWriter writer, final Property property, final String elementName, final boolean includeName) throws XMLStreamException { writer.writeStartElement(elementName); ModelNode node = property.getValue(); if (includeName) { writer.writeAttribute(Attribute.NAME.getLocalName(), property.getName()); } writeCountElement(PoolAttributeDefinitions.MAX_THREADS, node, writer); writeTime(writer, node, Element.KEEPALIVE_TIME); writeRef(writer, node, Element.THREAD_FACTORY, THREAD_FACTORY); writer.writeEndElement(); } private void writeRef(final XMLExtendedStreamWriter writer, final ModelNode node, Element element, String name) throws XMLStreamException { if (node.hasDefined(name)) { writer.writeStartElement(element.getLocalName()); writeAttribute(writer, Attribute.NAME, node.get(name)); writer.writeEndElement(); } } private void writeTime(final XMLExtendedStreamWriter writer, final ModelNode node, Element element) throws XMLStreamException { if (node.hasDefined(element.getLocalName())) { writer.writeStartElement(element.getLocalName()); ModelNode keepalive = node.get(element.getLocalName()); if (keepalive.hasDefined(TIME)) { writeAttribute(writer, Attribute.TIME, keepalive.get(TIME)); } if (keepalive.hasDefined(UNIT)) { writeAttributeLowerCaseValue(writer, Attribute.UNIT, keepalive.get(UNIT)); } writer.writeEndElement(); } } private void writeAttribute(final XMLExtendedStreamWriter writer, final Attribute attr, final ModelNode value) throws XMLStreamException { writer.writeAttribute(attr.getLocalName(), value.asString()); } private void writeAttributeLowerCaseValue(final XMLExtendedStreamWriter writer, final Attribute attr, final ModelNode value) throws XMLStreamException { writer.writeAttribute(attr.getLocalName(), value.asString().toLowerCase(Locale.ENGLISH)); } }