Skip to content

Commit

Permalink
Merge pull request #6206 from michpetrov/wfcore-7004
Browse files Browse the repository at this point in the history
WFCORE-7004: use custom parser over default
  • Loading branch information
yersan authored Oct 14, 2024
2 parents 29bbb43 + 3dc2df7 commit f8eca17
Show file tree
Hide file tree
Showing 8 changed files with 264 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ private PersistentResourceXMLDescription(PersistentResourceXMLBuilder builder)
LinkedHashMap<String, AttributeDefinition> 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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand All @@ -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 {
Expand All @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -475,14 +474,18 @@ 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<AttributeDefinition> attributes, String group) throws XMLStreamException {
boolean started = false;

//we sort attributes to make sure that attributes that marshall to elements are last
List<AttributeDefinition> sortedAds = new ArrayList<>(attributes.size());
List<AttributeDefinition> elementAds = null;
for (AttributeDefinition ad : attributes) {
if (ad.getParser().isParseAsElement()) {
if (getAttributeParser(ad).isParseAsElement()) {
if (elementAds == null) {
elementAds = new ArrayList<>();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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));
}
}
Original file line number Diff line number Diff line change
@@ -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));
}
}

}
Original file line number Diff line number Diff line change
@@ -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<ElementOrderSubsystemSchema> {
VERSION_1_0;
private final VersionedNamespace<IntVersion, ElementOrderSubsystemSchema> namespace = SubsystemSchema.createSubsystemURN(ElementOrderSubsystemResourceDefinition.SUBSYSTEM_NAME, new IntVersion(1));

@Override
public VersionedNamespace<IntVersion, ElementOrderSubsystemSchema> 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();
}
}
Original file line number Diff line number Diff line change
@@ -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());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<subsystem xmlns="urn:wildfly:element-order:1.0">
<group name="attrs-before-children">
<attribute>abc</attribute>
<attribute2>cdef</attribute2>
<child name="ijk"/>
<child2 name="mnop"/>
</group>
<group name="children-before-attrs">
<child name="abc"/>
<child2 name="cdef"/>
<attribute>ijk</attribute>
<attribute2>mnop</attribute2>
</group>
<group name="mixed">
<child name="abc"/>
<attribute2>cdef</attribute2>
<child2 name="ijk"/>
<attribute>mnop</attribute>
</group>
</subsystem>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:wildfly:element-order:1.0"
xmlns="urn:wildfly:element-order:1.0"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
version="1.0">

<xs:element name="subsystem" type="subsystem"/>

<xs:complexType name="subsystem">
<xs:sequence maxOccurs="unbounded">
<xs:element name="group" type="group"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="group">
<xs:all>
<xs:element name="attribute" type="xs:token"/>
<xs:element name="attribute2" type="xs:token"/>
<xs:element name="child" type="child" />
<xs:element name="child2" type="child" />
</xs:all>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>

<xs:complexType name="child">
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
</xs:schema>

0 comments on commit f8eca17

Please sign in to comment.