From: Robert Varga Date: Wed, 14 Dec 2022 01:55:59 +0000 (+0100) Subject: Clean up ModifyAction X-Git-Tag: v5.0.0~63 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=a3b5e80c0cbc973002b23f02d44b8548fefc9c05;p=netconf.git Clean up ModifyAction Document ModifyAction and modernize it. This allows a number of users to rely on new interfaces, eliminating interactions with Locale. Change-Id: If471c823e38c363e06a69cfd05923cdcb2f68a1a Signed-off-by: Robert Varga --- diff --git a/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/Datastore.java b/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/Datastore.java index 4a8878cd5e..671fadfc3b 100644 --- a/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/Datastore.java +++ b/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/Datastore.java @@ -5,9 +5,9 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ - package org.opendaylight.netconf.mdsal.connector.ops; +// FIXME: document, rename to LegacyDatastore (as per NMDA), add XML interaction values public enum Datastore { candidate, running } diff --git a/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/EditConfig.java b/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/EditConfig.java index 1156c99ff2..8d43838c56 100644 --- a/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/EditConfig.java +++ b/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/EditConfig.java @@ -7,13 +7,13 @@ */ package org.opendaylight.netconf.mdsal.connector.ops; -import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; import java.util.List; -import java.util.ListIterator; import java.util.concurrent.ExecutionException; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction; +import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteOperations; import org.opendaylight.netconf.api.DocumentedException; import org.opendaylight.netconf.api.ModifyAction; import org.opendaylight.netconf.api.xml.XmlElement; @@ -24,51 +24,47 @@ import org.opendaylight.yangtools.yang.common.ErrorSeverity; import org.opendaylight.yangtools.yang.common.ErrorTag; import org.opendaylight.yangtools.yang.common.ErrorType; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.Builders; import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; public final class EditConfig extends AbstractEdit { - private static final Logger LOG = LoggerFactory.getLogger(EditConfig.class); - private static final String OPERATION_NAME = "edit-config"; - private static final String DEFAULT_OPERATION_KEY = "default-operation"; + private static final String DEFAULT_OPERATION = "default-operation"; + private final TransactionProvider transactionProvider; public EditConfig(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext, final TransactionProvider transactionProvider) { super(netconfSessionIdForReporting, schemaContext); - this.transactionProvider = transactionProvider; + this.transactionProvider = requireNonNull(transactionProvider); + } + + @Override + protected String getOperationName() { + return OPERATION_NAME; } @Override protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws DocumentedException { - final XmlElement targetElement = extractTargetElement(operationElement, OPERATION_NAME); - final Datastore targetDatastore = Datastore.valueOf(targetElement.getName()); - if (targetDatastore == Datastore.running) { + if (Datastore.valueOf(extractTargetElement(operationElement, OPERATION_NAME).getName()) == Datastore.running) { throw new DocumentedException("edit-config on running datastore is not supported", ErrorType.PROTOCOL, ErrorTag.OPERATION_NOT_SUPPORTED, ErrorSeverity.ERROR); } - final ModifyAction defaultAction = getDefaultOperation(operationElement); - - final XmlElement configElement = getConfigElement(operationElement); - - for (final XmlElement element : configElement.getChildElements()) { - final SplittingNormalizedNodeMetadataStreamWriter writer = new SplittingNormalizedNodeMetadataStreamWriter( - defaultAction); + final var defaultAction = getDefaultOperation(operationElement); + for (var element : getConfigElement(operationElement).getChildElements()) { + final var writer = new SplittingNormalizedNodeMetadataStreamWriter(defaultAction); parseIntoNormalizedNode(getSchemaNodeFromNamespace(element.getNamespace(), element), element, writer); executeOperations(writer.getDataTreeChanges()); } @@ -77,19 +73,18 @@ public final class EditConfig extends AbstractEdit { } private void executeOperations(final List changes) throws DocumentedException { - final DOMDataTreeReadWriteTransaction rwTx = transactionProvider.getOrCreateTransaction(); - final ListIterator iterator = changes.listIterator(changes.size()); - + final var rwTx = transactionProvider.getOrCreateTransaction(); + final var iterator = changes.listIterator(changes.size()); while (iterator.hasPrevious()) { - final DataTreeChange dtc = iterator.previous(); - executeChange(rwTx, dtc); + executeChange(rwTx, iterator.previous()); } } + // FIXME: we should have proper ReadWriteOperations private void executeChange(final DOMDataTreeReadWriteTransaction rwtx, final DataTreeChange change) throws DocumentedException { - final YangInstanceIdentifier path = change.getPath(); - final NormalizedNode changeData = change.getChangeRoot(); + final var path = change.getPath(); + final var changeData = change.getChangeRoot(); switch (change.getAction()) { case NONE: return; @@ -99,6 +94,7 @@ public final class EditConfig extends AbstractEdit { break; case CREATE: try { + // FIXME: synchronous operation: can we get a rwTx.create() with a per-operation result instead? if (rwtx.exists(LogicalDatastoreType.CONFIGURATION, path).get()) { throw new DocumentedException("Data already exists, cannot execute CREATE operation", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS, ErrorSeverity.ERROR); @@ -115,6 +111,8 @@ public final class EditConfig extends AbstractEdit { break; case DELETE: try { + // FIXME: synchronous operation: can we get a rwTx.delete() semantics with a per-operation result + // instead? if (!rwtx.exists(LogicalDatastoreType.CONFIGURATION, path).get()) { throw new DocumentedException("Data is missing, cannot execute DELETE operation", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, ErrorSeverity.ERROR); @@ -132,60 +130,40 @@ public final class EditConfig extends AbstractEdit { } } - private void mergeParentMixin(final DOMDataTreeReadWriteTransaction rwtx, final YangInstanceIdentifier path, + private void mergeParentMixin(final DOMDataTreeWriteOperations rwtx, final YangInstanceIdentifier path, final NormalizedNode change) { - final YangInstanceIdentifier parentNodeYid = path.getParent(); + final var parentNodeYid = path.getParent(); if (change instanceof MapEntryNode) { - final DataSchemaNode schemaNode = DataSchemaContextTree.from(schemaContext.getCurrentContext()) + final var dataSchemaNode = DataSchemaContextTree.from(schemaContext.getCurrentContext()) .findChild(parentNodeYid) .orElseThrow(() -> new IllegalStateException("Cannot find schema for " + parentNodeYid)) .getDataSchemaNode(); // we should have the schema node that points to the parent list now, enforce it - checkState(schemaNode instanceof ListSchemaNode, "Schema node is not pointing to a list."); - - //merge empty ordered or unordered map - if (((ListSchemaNode) schemaNode).isUserOrdered()) { - final MapNode mixinNode = Builders.orderedMapBuilder() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifier( - parentNodeYid.getLastPathArgument().getNodeType())) - .build(); - rwtx.merge(LogicalDatastoreType.CONFIGURATION, parentNodeYid, mixinNode); - return; + if (!(dataSchemaNode instanceof ListSchemaNode listSchemaNode)) { + throw new IllegalStateException("Schema node is not pointing to a list"); } - final MapNode mixinNode = Builders.mapBuilder() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifier( - parentNodeYid.getLastPathArgument().getNodeType())) - .build(); - rwtx.merge(LogicalDatastoreType.CONFIGURATION, parentNodeYid, mixinNode); - } else if (parentNodeYid.getLastPathArgument() instanceof YangInstanceIdentifier.AugmentationIdentifier) { + // merge empty ordered or unordered map + rwtx.merge(LogicalDatastoreType.CONFIGURATION, parentNodeYid, + (listSchemaNode.isUserOrdered() ? Builders.orderedMapBuilder() : Builders.mapBuilder()) + .withNodeIdentifier(new NodeIdentifier(parentNodeYid.getLastPathArgument().getNodeType())) + .build()); + } else if (parentNodeYid.getLastPathArgument() instanceof AugmentationIdentifier augId) { // merge empty augmentation node - final YangInstanceIdentifier.AugmentationIdentifier augmentationYid = - (YangInstanceIdentifier.AugmentationIdentifier) parentNodeYid.getLastPathArgument(); - final AugmentationNode augmentationNode = Builders.augmentationBuilder() - .withNodeIdentifier(augmentationYid).build(); - rwtx.merge(LogicalDatastoreType.CONFIGURATION, parentNodeYid, augmentationNode); + rwtx.merge(LogicalDatastoreType.CONFIGURATION, parentNodeYid, Builders.augmentationBuilder() + .withNodeIdentifier(augId) + .build()); } } private static ModifyAction getDefaultOperation(final XmlElement operationElement) throws DocumentedException { - final NodeList elementsByTagName = getElementsByTagName(operationElement, DEFAULT_OPERATION_KEY); - if (elementsByTagName.getLength() == 0) { - return ModifyAction.MERGE; - } else if (elementsByTagName.getLength() > 1) { - throw new DocumentedException("Multiple " + DEFAULT_OPERATION_KEY + " elements", ErrorType.RPC, + final var elementsByTagName = getElementsByTagName(operationElement, DEFAULT_OPERATION); + return switch (elementsByTagName.getLength()) { + case 0 -> ModifyAction.MERGE; + case 1 -> ModifyAction.ofXmlValue(elementsByTagName.item(0).getTextContent()); + default -> throw new DocumentedException("Multiple " + DEFAULT_OPERATION + " elements", ErrorType.RPC, ErrorTag.UNKNOWN_ATTRIBUTE, ErrorSeverity.ERROR); - } else { - return ModifyAction.fromXmlValue(elementsByTagName.item(0).getTextContent()); - } - - } - - @Override - protected String getOperationName() { - return OPERATION_NAME; + }; } } diff --git a/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/SplittingNormalizedNodeMetadataStreamWriter.java b/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/SplittingNormalizedNodeMetadataStreamWriter.java index 39c7fe7ec8..61bbbda8df 100644 --- a/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/SplittingNormalizedNodeMetadataStreamWriter.java +++ b/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/SplittingNormalizedNodeMetadataStreamWriter.java @@ -79,13 +79,12 @@ final class SplittingNormalizedNodeMetadataStreamWriter implements NormalizedNod @Override public void metadata(final ImmutableMap metadata) throws IOException { - final Object operation = metadata.get(OPERATION_ATTRIBUTE); - if (operation != null) { - checkState(operation instanceof String, "Unexpected operation attribute value %s", operation); - final ModifyAction newAction = ModifyAction.fromXmlValue((String) operation); - currentAction = newAction; + final var operation = metadata.get(OPERATION_ATTRIBUTE); + if (operation instanceof String str) { + currentAction = ModifyAction.ofXmlValue(str); + } else if (operation != null) { + throw new IllegalStateException("Unexpected operation attribute value " + operation); } - writer.metadata(filterMeta(metadata)); } @@ -186,7 +185,7 @@ final class SplittingNormalizedNodeMetadataStreamWriter implements NormalizedNod @Override public void endNode() throws IOException { - final ModifyAction prevAction = actions.peek(); + final var prevAction = actions.peek(); if (prevAction != null) { // We only split out a builder if we a changing action relative to parent and we are not inside // a remove/delete operation diff --git a/netconf/netconf-api/src/main/java/org/opendaylight/netconf/api/ModifyAction.java b/netconf/netconf-api/src/main/java/org/opendaylight/netconf/api/ModifyAction.java index 0ee9956b60..ca8bc1d340 100644 --- a/netconf/netconf-api/src/main/java/org/opendaylight/netconf/api/ModifyAction.java +++ b/netconf/netconf-api/src/main/java/org/opendaylight/netconf/api/ModifyAction.java @@ -7,53 +7,101 @@ */ package org.opendaylight.netconf.api; -import java.util.Arrays; +import static java.util.Objects.requireNonNull; +import org.eclipse.jdt.annotation.NonNull; + +/** + * NETCONF modification actions, as allowed for in {@code operation} and {@code default-operation} attributes of + * {@code } operation, as defined in + * RFC6241 section 7.2. + * + *

+ * This concept is uncharacteristically bound to two separate semantics, but for a good reason: at the end of the day we + * want to know what the effective operation is. + */ public enum ModifyAction { - MERGE(true), REPLACE(true), CREATE(false), DELETE(false), REMOVE(false), NONE(true, false); - - public static ModifyAction fromXmlValue(final String xmlNameOfAction) { - switch (xmlNameOfAction) { - case "merge": - return MERGE; - case "replace": - return REPLACE; - case "remove": - return REMOVE; - case "delete": - return DELETE; - case "create": - return CREATE; - case "none": - return NONE; - default: - throw new IllegalArgumentException("Unknown operation " + xmlNameOfAction + " available operations " - + Arrays.toString(ModifyAction.values())); - } - } + // operation and default-operation + MERGE("merge", true, true), + REPLACE("replace", true, true), + // operation only + CREATE("create", true, false), + DELETE("delete", true, false), + REMOVE("remove", true, false), + + // default-operation-only + NONE("none", false, true); + + private final @NonNull String xmlValue; + private final boolean isDefaultOperation; + private final boolean isOperation; - private final boolean asDefaultPermitted; - private final boolean onElementPermitted; + ModifyAction(final String xmlValue, final boolean isOperation, final boolean isDefaultOperation) { + this.xmlValue = requireNonNull(xmlValue); + this.isDefaultOperation = isDefaultOperation; + this.isOperation = isOperation; + } - ModifyAction(final boolean asDefaultPermitted, final boolean onElementPermitted) { - this.asDefaultPermitted = asDefaultPermitted; - this.onElementPermitted = onElementPermitted; + /** + * Return the {@link ModifyAction} corresponding to a {@link #xmlValue}. + * + * @param xmlValue XML attribute or element value + * @return A {@link ModifyAction} + * @throws NullPointerException if {@code xmlValue} is {@code null} + * @throws IllegalArgumentException if {@code xmlValue} is not recognized + */ + public static @NonNull ModifyAction ofXmlValue(final String xmlValue) { + return switch (xmlValue) { + case "merge" -> MERGE; + case "replace" -> REPLACE; + case "remove" -> REMOVE; + case "delete" -> DELETE; + case "create" -> CREATE; + case "none" -> NONE; + default -> throw new IllegalArgumentException("Unknown operation " + xmlValue); + }; } - ModifyAction(final boolean asDefaultPermitted) { - this(asDefaultPermitted, true); + /** + * Return an XML string literal corresponding to this {@link ModifyAction}. + * + * @return An XML string literal + */ + public @NonNull String xmlValue() { + return xmlValue; } /** * Check if this operation is a candidate for {@code default-operation} argument. * - * @return True if this operation can be used as {@code default-operation}. + * @return {@code true} if this operation can be used as {@code default-operation}, {@code false} otherwise. + * @deprecated Use {@link #isDefaultOperation()} instead */ + @Deprecated(since = "5.0.0", forRemoval = true) public boolean isAsDefaultPermitted() { - return asDefaultPermitted; + return isDefaultOperation; + } + + /** + * Check if this operation is a candidate for {@code default-operation} argument. + * + * @return {@code true} if this operation can be used as {@code default-operation}, {@code false} otherwise. + */ + public boolean isDefaultOperation() { + return isDefaultOperation; } + @Deprecated(since = "5.0.0", forRemoval = true) public boolean isOnElementPermitted() { - return onElementPermitted; + return isOperation; + } + + /** + * Check if this operation is a candidate for {@code operation} attribute. + * + * @return {@code true} if this operation can be used as {@code operation}, {@code false} otherwise. + */ + public boolean isOperation() { + return isOperation; } } diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/util/SchemalessRpcStructureTransformer.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/util/SchemalessRpcStructureTransformer.java index 45058eb17c..7f4fa6b877 100644 --- a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/util/SchemalessRpcStructureTransformer.java +++ b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/util/SchemalessRpcStructureTransformer.java @@ -17,18 +17,13 @@ import static org.opendaylight.netconf.util.NetconfUtil.NETCONF_DATA_QNAME; import static org.opendaylight.netconf.util.NetconfUtil.appendListKeyNodes; import static org.opendaylight.netconf.util.NetconfUtil.writeSchemalessFilter; -import com.google.common.base.Preconditions; -import java.util.Collections; import java.util.List; -import java.util.Locale; -import java.util.Map.Entry; import java.util.Optional; import javax.xml.transform.dom.DOMSource; import org.opendaylight.netconf.api.DocumentedException; import org.opendaylight.netconf.api.ModifyAction; import org.opendaylight.netconf.api.xml.XmlElement; import org.opendaylight.netconf.api.xml.XmlUtil; -import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; @@ -37,7 +32,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.DOMSourceAnyxmlNode; import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -57,21 +51,21 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer { @Override public Optional selectFromDataStructure(final DataContainerChild data, final YangInstanceIdentifier path) { - Preconditions.checkArgument(data instanceof DOMSourceAnyxmlNode); - final List xmlElements = selectMatchingNodes( - getSourceElement(((DOMSourceAnyxmlNode)data).body()), path); - final Document result = XmlUtil.newDocument(); - final Element dataElement = - result.createElementNS(NETCONF_DATA_QNAME.getNamespace().toString(), NETCONF_DATA_QNAME.getLocalName()); + if (!(data instanceof DOMSourceAnyxmlNode anyxml)) { + throw new IllegalArgumentException("Unexpected data " + data.prettyTree()); + } + + final var result = XmlUtil.newDocument(); + final var dataElement = result.createElementNS(NETCONF_DATA_QNAME.getNamespace().toString(), + NETCONF_DATA_QNAME.getLocalName()); result.appendChild(dataElement); - for (XmlElement xmlElement : xmlElements) { + for (var xmlElement : selectMatchingNodes(getSourceElement(anyxml.body()), path)) { dataElement.appendChild(result.importNode(xmlElement.getDomElement(), true)); } - final DOMSourceAnyxmlNode resultAnyxml = Builders.anyXmlBuilder() - .withNodeIdentifier(NETCONF_DATA_NODEID) - .withValue(new DOMSource(result)) - .build(); - return Optional.of(resultAnyxml); + return Optional.of(Builders.anyXmlBuilder() + .withNodeIdentifier(NETCONF_DATA_NODEID) + .withValue(new DOMSource(result)) + .build()); } /** @@ -85,15 +79,16 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer { @Override public DOMSourceAnyxmlNode createEditConfigStructure(final Optional data, final YangInstanceIdentifier dataPath, final Optional operation) { - Preconditions.checkArgument(data.isPresent()); - Preconditions.checkArgument(data.get() instanceof DOMSourceAnyxmlNode); + final var dataValue = data.orElseThrow(); + if (!(dataValue instanceof DOMSourceAnyxmlNode anxmlData)) { + throw new IllegalArgumentException("Unexpected data " + dataValue.prettyTree()); + } - final DOMSourceAnyxmlNode anxmlData = (DOMSourceAnyxmlNode) data.get(); - final Document document = XmlUtil.newDocument(); - final Element dataNode = (Element) document.importNode(getSourceElement(anxmlData.body()), true); + final var document = XmlUtil.newDocument(); + final var dataNode = (Element) document.importNode(getSourceElement(anxmlData.body()), true); checkDataValidForPath(dataPath, dataNode); - final Element configElement = document.createElementNS(NETCONF_CONFIG_QNAME.getNamespace().toString(), + final var configElement = document.createElementNS(NETCONF_CONFIG_QNAME.getNamespace().toString(), NETCONF_CONFIG_QNAME.getLocalName()); document.appendChild(configElement); @@ -102,17 +97,18 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer { parentXmlStructure = dataNode; configElement.appendChild(parentXmlStructure); } else { - final List pathArguments = dataPath.getPathArguments(); - //last will be appended later - final List pathWithoutLast = pathArguments.subList(0, pathArguments.size() - 1); - parentXmlStructure = instanceIdToXmlStructure(pathWithoutLast, configElement); + final var pathArguments = dataPath.getPathArguments(); + // last will be appended later + parentXmlStructure = instanceIdToXmlStructure(pathArguments.subList(0, pathArguments.size() - 1), + configElement); } operation.ifPresent(modifyAction -> setOperationAttribute(modifyAction, document, dataNode)); //append data parentXmlStructure.appendChild(document.importNode(dataNode, true)); - return Builders.anyXmlBuilder().withNodeIdentifier(NETCONF_CONFIG_NODEID) - .withValue(new DOMSource(document.getDocumentElement())) - .build(); + return Builders.anyXmlBuilder() + .withNodeIdentifier(NETCONF_CONFIG_NODEID) + .withValue(new DOMSource(document.getDocumentElement())) + .build(); } /** @@ -123,37 +119,37 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer { */ @Override public AnyxmlNode toFilterStructure(final YangInstanceIdentifier path) { - final Document document = XmlUtil.newDocument(); - final Element filterElement = prepareFilterElement(document); - instanceIdToXmlStructure(path.getPathArguments(), filterElement); + final var document = XmlUtil.newDocument(); + instanceIdToXmlStructure(path.getPathArguments(), prepareFilterElement(document)); return buildFilterXmlNode(document); } @Override public AnyxmlNode toFilterStructure(final List fieldsFilters) { - final Document document = XmlUtil.newDocument(); - final Element filterElement = prepareFilterElement(document); - for (final FieldsFilter filter : fieldsFilters) { + final var document = XmlUtil.newDocument(); + final var filterElement = prepareFilterElement(document); + for (var filter : fieldsFilters) { writeSchemalessFilter(filter.path(), filter.fields(), filterElement); } return buildFilterXmlNode(document); } private static Element prepareFilterElement(final Document document) { - final String filterNs = NETCONF_FILTER_QNAME.getNamespace().toString(); - final Element filter = document.createElementNS(filterNs, NETCONF_FILTER_QNAME.getLocalName()); - final Attr a = document.createAttributeNS(filterNs, "type"); - a.setTextContent("subtree"); - filter.setAttributeNode(a); + // FIXME: use a constant + final var filterNs = NETCONF_FILTER_QNAME.getNamespace().toString(); + final var filter = document.createElementNS(filterNs, NETCONF_FILTER_QNAME.getLocalName()); + final var attr = document.createAttributeNS(filterNs, "type"); + attr.setTextContent("subtree"); + filter.setAttributeNode(attr); document.appendChild(filter); return filter; } private static AnyxmlNode buildFilterXmlNode(final Document document) { return Builders.anyXmlBuilder() - .withNodeIdentifier(NETCONF_FILTER_NODEID) - .withValue(new DOMSource(document.getDocumentElement())) - .build(); + .withNodeIdentifier(NETCONF_FILTER_NODEID) + .withValue(new DOMSource(document.getDocumentElement())) + .build(); } private static void checkDataValidForPath(final YangInstanceIdentifier dataPath, final Element dataNode) { @@ -161,9 +157,9 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer { if (dataPath.isEmpty()) { return; } - final XmlElement dataElement = XmlElement.fromDomElement(dataNode); - final PathArgument lastPathArgument = dataPath.getLastPathArgument(); - final QName nodeType = lastPathArgument.getNodeType(); + final var dataElement = XmlElement.fromDomElement(dataNode); + final var lastPathArgument = dataPath.getLastPathArgument(); + final var nodeType = lastPathArgument.getNodeType(); if (!nodeType.getNamespace().toString().equals(dataNode.getNamespaceURI()) || !nodeType.getLocalName().equals(dataElement.getName())) { throw new IllegalStateException( @@ -175,12 +171,10 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer { } private static void checkKeyValuesValidForPath(final XmlElement dataElement, final PathArgument lastPathArgument) { - final NodeIdentifierWithPredicates keyedId = (NodeIdentifierWithPredicates) lastPathArgument; - for (Entry entry : keyedId.entrySet()) { - QName qualifiedName = entry.getKey(); - final List key = - dataElement.getChildElementsWithinNamespace(qualifiedName.getLocalName(), - qualifiedName.getNamespace().toString()); + for (var entry : ((NodeIdentifierWithPredicates) lastPathArgument).entrySet()) { + final var qname = entry.getKey(); + final var key = dataElement.getChildElementsWithinNamespace(qname.getLocalName(), + qname.getNamespace().toString()); if (key.isEmpty()) { throw new IllegalStateException("No key present in xml"); } @@ -200,23 +194,23 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer { } private static void setOperationAttribute(final ModifyAction operation, final Document document, - final Element dataNode) { - final Attr operationAttribute = document.createAttributeNS(NETCONF_OPERATION_QNAME.getNamespace().toString(), + final Element dataNode) { + final var operationAttribute = document.createAttributeNS(NETCONF_OPERATION_QNAME.getNamespace().toString(), NETCONF_OPERATION_QNAME.getLocalName()); - operationAttribute.setTextContent(toOperationString(operation)); + operationAttribute.setTextContent(operation.xmlValue()); dataNode.setAttributeNode(operationAttribute); } private static Element instanceIdToXmlStructure(final List pathArguments, final Element data) { - final Document doc = data.getOwnerDocument(); - Element parent = data; - for (PathArgument pathArgument : pathArguments) { - final QName nodeType = pathArgument.getNodeType(); - final Element element = doc.createElementNS(nodeType.getNamespace().toString(), nodeType.getLocalName()); + final var doc = data.getOwnerDocument(); + var parent = data; + for (var pathArgument : pathArguments) { + final var nodeType = pathArgument.getNodeType(); + final var element = doc.createElementNS(nodeType.getNamespace().toString(), nodeType.getLocalName()); parent.appendChild(element); //if path argument is list id, add also keys to resulting xml - if (pathArgument instanceof NodeIdentifierWithPredicates) { - appendListKeyNodes(element, (NodeIdentifierWithPredicates) pathArgument); + if (pathArgument instanceof NodeIdentifierWithPredicates nip) { + appendListKeyNodes(element, nip); } parent = element; } @@ -224,32 +218,24 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer { } private static List selectMatchingNodes(final Element domElement, final YangInstanceIdentifier path) { - XmlElement element = XmlElement.fromDomElement(domElement); - for (PathArgument pathArgument : path.getPathArguments()) { - List childElements = element.getChildElements(pathArgument.getNodeType().getLocalName()); + var element = XmlElement.fromDomElement(domElement); + for (var pathArgument : path.getPathArguments()) { + var childElements = element.getChildElements(pathArgument.getNodeType().getLocalName()); if (childElements.size() == 1) { element = childElements.get(0); } else { return childElements; } } - return Collections.singletonList(element); - } - - private static String toOperationString(final ModifyAction operation) { - return operation.name().toLowerCase(Locale.ROOT); + return List.of(element); } private static Element getSourceElement(final DOMSource source) { - final Node node = source.getNode(); - switch (node.getNodeType()) { - case Node.DOCUMENT_NODE: - return ((Document)node).getDocumentElement(); - case Node.ELEMENT_NODE: - return (Element) node; - default: - throw new IllegalStateException("DOMSource node must be document or element."); - } + final var node = source.getNode(); + return switch (node.getNodeType()) { + case Node.DOCUMENT_NODE -> ((Document) node).getDocumentElement(); + case Node.ELEMENT_NODE -> (Element) node; + default -> throw new IllegalStateException("DOMSource node must be document or element."); + }; } - }