From 3dc2df740d029dc9d3d03a53ef9f4a84e1a2e54b Mon Sep 17 00:00:00 2001 From: Michal Petrov Date: Fri, 27 Sep 2024 16:18:12 +0200 Subject: [PATCH] WFCORE-7004: use custom parser over default --- .../jboss/as/controller/AttributeParser.java | 2 +- .../PersistentResourceXMLDescription.java | 21 +++-- .../ElementOrderSubsystemExtension.java | 33 +++++++ ...ementOrderSubsystemResourceDefinition.java | 85 +++++++++++++++++++ .../ElementOrderSubsystemSchema.java | 36 ++++++++ .../ElementOrderSubsystemTestCase.java | 47 ++++++++++ .../test/elementorder/element-order-1.0.xml | 20 +++++ .../schema/wildfly-element-order_1_0.xsd | 30 +++++++ 8 files changed, 264 insertions(+), 10 deletions(-) create mode 100644 subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemExtension.java create mode 100644 subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemResourceDefinition.java create mode 100644 subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemSchema.java create mode 100644 subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemTestCase.java create mode 100644 subsystem-test/tests/src/test/resources/org/jboss/as/subsystem/test/elementorder/element-order-1.0.xml create mode 100644 subsystem-test/tests/src/test/resources/schema/wildfly-element-order_1_0.xsd diff --git a/controller/src/main/java/org/jboss/as/controller/AttributeParser.java b/controller/src/main/java/org/jboss/as/controller/AttributeParser.java index 96dd3238a33..3a4583df2c9 100644 --- a/controller/src/main/java/org/jboss/as/controller/AttributeParser.java +++ b/controller/src/main/java/org/jboss/as/controller/AttributeParser.java @@ -89,7 +89,7 @@ public boolean isParseAsElement() { } public void parseElement(final AttributeDefinition attribute, final XMLExtendedStreamReader reader, ModelNode operation) throws XMLStreamException { - + throw new UnsupportedOperationException(); } public String getXmlName(final AttributeDefinition attribute){ diff --git a/controller/src/main/java/org/jboss/as/controller/PersistentResourceXMLDescription.java b/controller/src/main/java/org/jboss/as/controller/PersistentResourceXMLDescription.java index 3e7d90d5665..ff42a337dd1 100644 --- a/controller/src/main/java/org/jboss/as/controller/PersistentResourceXMLDescription.java +++ b/controller/src/main/java/org/jboss/as/controller/PersistentResourceXMLDescription.java @@ -101,7 +101,7 @@ private PersistentResourceXMLDescription(PersistentResourceXMLBuilder builder) LinkedHashMap attrs = new LinkedHashMap<>(); for (AttributeDefinition ad : builder.attributeList) { attrs.put(ad.getXmlName(), ad); - AttributeParser ap = ad.getParser(); + AttributeParser ap = builder.attributeParsers.getOrDefault(ad.getXmlName(), ad.getParser()); if (ap != null && ap.isParseAsElement()) { attributeElements.put(ap.getXmlName(ad), ad); } @@ -205,7 +205,7 @@ private String parseAttributeGroups(final XMLExtendedStreamReader reader, ModelN if (element || attributeGroups.contains(localName)) { if (element) { AttributeDefinition ad = attributeElements.get(localName); - ad.getParser().parseElement(ad, reader, op); + getAttributeParser(ad).parseElement(ad, reader, op); final String newLocalName = reader.getLocalName(); if (attributeGroups.contains(newLocalName)) { parseGroup(reader, op, wildcard); @@ -240,7 +240,7 @@ private void parseGroup(XMLExtendedStreamReader reader, ModelNode op, boolean wi while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { AttributeDefinition ad = groupAttrs.get(reader.getLocalName()); if (ad != null) { - ad.getParser().parseElement(ad, reader, op); + getAttributeParser(ad).parseElement(ad, reader, op); } else { throw ParseUtils.unexpectedElement(reader); } @@ -257,7 +257,7 @@ private String parseAttributes(final XMLExtendedStreamReader reader, ModelNode o name = value; } else if (attributes.containsKey(attributeName)) { AttributeDefinition def = attributes.get(attributeName); - AttributeParser parser = attributeParsers.getOrDefault(attributeName, def.getParser()); + AttributeParser parser = getAttributeParser(def); assert parser != null; parser.parseAndSetParameter(def, value, op, reader); } else { @@ -273,11 +273,10 @@ private String parseAttributes(final XMLExtendedStreamReader reader, ModelNode o do { AttributeDefinition ad = attributeElements.get(reader.getLocalName()); if (ad != null) { - AttributeParser parser = attributeParsers.getOrDefault(ad.getXmlName(), ad.getParser()); - parser.parseElement(ad, reader, op); + getAttributeParser(ad).parseElement(ad, reader, op); } else { childAlreadyRead = true; - return name; //this means we only have children left, return so child handling logic can take over + return name; //this possibly means we only have children left, return so child handling logic can take over } childAlreadyRead = true; } while (!reader.getLocalName().equals(originalStartElement) && reader.hasNext() && reader.nextTag() != XMLStreamConstants.END_ELEMENT); @@ -324,7 +323,7 @@ private void parseChildren(final XMLExtendedStreamReader reader, PathAddress par if (child != null) { child.parse(reader, parentAddress, list); } else if ((elementAd = attributeElements.get(localName)) != null) { - elementAd.getParser().parseElement(elementAd, reader, op); + getAttributeParser(elementAd).parseElement(elementAd, reader, op); } else if ((child = customChildParsers.get(localName)) != null) { child.parse(reader, parentAddress, list); } else { @@ -475,6 +474,10 @@ private void persistAttributes(XMLExtendedStreamWriter writer, ModelNode model) } } + private AttributeParser getAttributeParser(AttributeDefinition ad) { + return attributeParsers.getOrDefault(ad.getXmlName(), ad.getParser()); + } + private void marshallAttributes(XMLExtendedStreamWriter writer, ModelNode model, Collection attributes, String group) throws XMLStreamException { boolean started = false; @@ -482,7 +485,7 @@ private void marshallAttributes(XMLExtendedStreamWriter writer, ModelNode model, List sortedAds = new ArrayList<>(attributes.size()); List elementAds = null; for (AttributeDefinition ad : attributes) { - if (ad.getParser().isParseAsElement()) { + if (getAttributeParser(ad).isParseAsElement()) { if (elementAds == null) { elementAds = new ArrayList<>(); } diff --git a/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemExtension.java b/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemExtension.java new file mode 100644 index 00000000000..1fd269b3824 --- /dev/null +++ b/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemExtension.java @@ -0,0 +1,33 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.as.subsystem.test.elementorder; + +import org.jboss.as.controller.Extension; +import org.jboss.as.controller.ExtensionContext; +import org.jboss.as.controller.ModelVersion; +import org.jboss.as.controller.PersistentResourceXMLDescriptionWriter; +import org.jboss.as.controller.SubsystemRegistration; +import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler; +import org.jboss.as.controller.parsing.ExtensionParsingContext; +import org.jboss.as.controller.registry.ManagementResourceRegistration; + +import java.util.EnumSet; + +public class ElementOrderSubsystemExtension implements Extension { + + @Override + public void initialize(ExtensionContext context) { + SubsystemRegistration subsystem = context.registerSubsystem(ElementOrderSubsystemResourceDefinition.SUBSYSTEM_NAME, ModelVersion.create(1)); + ManagementResourceRegistration registration = subsystem.registerSubsystemModel(new ElementOrderSubsystemResourceDefinition()); + registration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE); + + subsystem.registerXMLElementWriter(new PersistentResourceXMLDescriptionWriter(ElementOrderSubsystemSchema.VERSION_1_0)); + } + + @Override + public void initializeParsers(ExtensionParsingContext context) { + context.setSubsystemXmlMappings(ElementOrderSubsystemResourceDefinition.SUBSYSTEM_NAME, EnumSet.of(ElementOrderSubsystemSchema.VERSION_1_0)); + } +} diff --git a/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemResourceDefinition.java b/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemResourceDefinition.java new file mode 100644 index 00000000000..629ebca8bb7 --- /dev/null +++ b/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemResourceDefinition.java @@ -0,0 +1,85 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.as.subsystem.test.elementorder; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PathElement; +import org.jboss.as.controller.ReloadRequiredAddStepHandler; +import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; +import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler; +import org.jboss.as.controller.ResourceRegistration; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleResourceDefinition; +import org.jboss.as.controller.descriptions.ModelDescriptionConstants; +import org.jboss.as.controller.descriptions.NonResolvingResourceDescriptionResolver; +import org.jboss.as.controller.registry.ManagementResourceRegistration; +import org.jboss.dmr.ModelType; + +public class ElementOrderSubsystemResourceDefinition extends SimpleResourceDefinition { + static final String SUBSYSTEM_NAME = "element-order"; + static final PathElement PATH = PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, SUBSYSTEM_NAME); + static final ResourceRegistration GROUP_REGISTRATION = ResourceRegistration.of(PathElement.pathElement("group")); + static final ResourceRegistration CHILD_REGISTRATION = ResourceRegistration.of(PathElement.pathElement("child")); + static final ResourceRegistration CHILD_2_REGISTRATION = ResourceRegistration.of(PathElement.pathElement("child2")); + + static final AttributeDefinition ATTRIBUTE = new SimpleAttributeDefinitionBuilder("attribute", ModelType.STRING) + .setRequired(false) + .build(); + + static final AttributeDefinition ATTRIBUTE_2 = new SimpleAttributeDefinitionBuilder("attribute2", ModelType.STRING) + .setRequired(false) + .build(); + + ElementOrderSubsystemResourceDefinition() { + super(new Parameters(PATH, NonResolvingResourceDescriptionResolver.INSTANCE) + .setAddHandler(ReloadRequiredAddStepHandler.INSTANCE) + .setRemoveHandler(ReloadRequiredRemoveStepHandler.INSTANCE)); + } + + @Override + public void registerChildren(ManagementResourceRegistration registration) { + registration.registerSubModel(new GroupResourceDefinition()); + } + + public class GroupResourceDefinition extends SimpleResourceDefinition { + + GroupResourceDefinition() { + super(new Parameters(GROUP_REGISTRATION, NonResolvingResourceDescriptionResolver.INSTANCE) + .setAddHandler(ReloadRequiredAddStepHandler.INSTANCE) + .setRemoveHandler(ReloadRequiredRemoveStepHandler.INSTANCE)); + } + + @Override + public void registerAttributes(ManagementResourceRegistration registration) { + registration.registerReadWriteAttribute(ATTRIBUTE, null, ReloadRequiredWriteAttributeHandler.INSTANCE); + registration.registerReadWriteAttribute(ATTRIBUTE_2, null, ReloadRequiredWriteAttributeHandler.INSTANCE); + } + + @Override + public void registerChildren(ManagementResourceRegistration registration) { + registration.registerSubModel(new ChildResourceDefinition()); + registration.registerSubModel(new Child2ResourceDefinition()); + } + } + + public class ChildResourceDefinition extends SimpleResourceDefinition { + + ChildResourceDefinition() { + super(new Parameters(CHILD_REGISTRATION, NonResolvingResourceDescriptionResolver.INSTANCE) + .setAddHandler(ReloadRequiredAddStepHandler.INSTANCE) + .setRemoveHandler(ReloadRequiredRemoveStepHandler.INSTANCE)); + } + } + + public class Child2ResourceDefinition extends SimpleResourceDefinition { + + Child2ResourceDefinition() { + super(new Parameters(CHILD_2_REGISTRATION, NonResolvingResourceDescriptionResolver.INSTANCE) + .setAddHandler(ReloadRequiredAddStepHandler.INSTANCE) + .setRemoveHandler(ReloadRequiredRemoveStepHandler.INSTANCE)); + } + } + +} diff --git a/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemSchema.java b/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemSchema.java new file mode 100644 index 00000000000..ec0623a5f64 --- /dev/null +++ b/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemSchema.java @@ -0,0 +1,36 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.as.subsystem.test.elementorder; + +import org.jboss.as.controller.AttributeMarshallers; +import org.jboss.as.controller.AttributeParsers; +import org.jboss.as.controller.PersistentResourceXMLDescription; +import org.jboss.as.controller.PersistentSubsystemSchema; +import org.jboss.as.controller.SubsystemSchema; +import org.jboss.as.controller.xml.VersionedNamespace; +import org.jboss.staxmapper.IntVersion; + +public enum ElementOrderSubsystemSchema implements PersistentSubsystemSchema { + VERSION_1_0; + private final VersionedNamespace namespace = SubsystemSchema.createSubsystemURN(ElementOrderSubsystemResourceDefinition.SUBSYSTEM_NAME, new IntVersion(1)); + + @Override + public VersionedNamespace getNamespace() { + return this.namespace; + } + + @Override + public PersistentResourceXMLDescription getXMLDescription() { + PersistentResourceXMLDescription.Factory factory = PersistentResourceXMLDescription.factory(this); + PersistentResourceXMLDescription.Builder builder = factory.builder(ElementOrderSubsystemResourceDefinition.PATH); + PersistentResourceXMLDescription.Builder groupBuilder = factory.builder(ElementOrderSubsystemResourceDefinition.GROUP_REGISTRATION); + groupBuilder.addAttribute(ElementOrderSubsystemResourceDefinition.ATTRIBUTE, AttributeParsers.SIMPLE_ELEMENT, AttributeMarshallers.SIMPLE_ELEMENT); + groupBuilder.addAttribute(ElementOrderSubsystemResourceDefinition.ATTRIBUTE_2, AttributeParsers.SIMPLE_ELEMENT, AttributeMarshallers.SIMPLE_ELEMENT); + groupBuilder.addChild(factory.builder(ElementOrderSubsystemResourceDefinition.CHILD_REGISTRATION).build()); + groupBuilder.addChild(factory.builder(ElementOrderSubsystemResourceDefinition.CHILD_2_REGISTRATION).build()); + builder.addChild(groupBuilder.build()); + return builder.build(); + } +} diff --git a/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemTestCase.java b/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemTestCase.java new file mode 100644 index 00000000000..5ed8f38ada7 --- /dev/null +++ b/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/elementorder/ElementOrderSubsystemTestCase.java @@ -0,0 +1,47 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.as.subsystem.test.elementorder; + +import org.jboss.as.subsystem.test.AbstractSubsystemBaseTest; + +import javax.xml.stream.XMLStreamException; +import java.io.IOException; + +import static org.junit.Assert.fail; + +/** + * Test for checking an XML configuration will be correctly parsed when the elements are written in non-default order if the schema allows it + * Default order = attribute elements before children elements + */ +public class ElementOrderSubsystemTestCase extends AbstractSubsystemBaseTest { + + public ElementOrderSubsystemTestCase() { + super(ElementOrderSubsystemResourceDefinition.SUBSYSTEM_NAME, new ElementOrderSubsystemExtension()); + } + + @Override + protected String getSubsystemXml() throws IOException { + return readResource("element-order-1.0.xml"); + } + + @Override + protected String getSubsystemXsdPath() { + return "schema/wildfly-element-order_1_0.xsd"; + } + + @Override + protected void compareXml(String configId, String original, String marshalled) { + // do nothing, compareXml imposes the default order + } + + @Override + public void testSubsystem() throws Exception { + try { + super.testSubsystem(); + } catch (UnsupportedOperationException | XMLStreamException e) { + fail("Parser failed: " + e.getMessage()); + } + } +} diff --git a/subsystem-test/tests/src/test/resources/org/jboss/as/subsystem/test/elementorder/element-order-1.0.xml b/subsystem-test/tests/src/test/resources/org/jboss/as/subsystem/test/elementorder/element-order-1.0.xml new file mode 100644 index 00000000000..407df80bdd9 --- /dev/null +++ b/subsystem-test/tests/src/test/resources/org/jboss/as/subsystem/test/elementorder/element-order-1.0.xml @@ -0,0 +1,20 @@ + + + abc + cdef + + + + + + + ijk + mnop + + + + cdef + + mnop + + diff --git a/subsystem-test/tests/src/test/resources/schema/wildfly-element-order_1_0.xsd b/subsystem-test/tests/src/test/resources/schema/wildfly-element-order_1_0.xsd new file mode 100644 index 00000000000..6d88d84006c --- /dev/null +++ b/subsystem-test/tests/src/test/resources/schema/wildfly-element-order_1_0.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + +