X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=netconf%2Fmdsal-netconf-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetconf%2Fmdsal%2Fconnector%2Fops%2Fget%2FAbstractGet.java;h=c323069e12b3dee5ca98e74264240a40cdb534af;hb=81fe6df18b2f554be7d9f73d56fdc8a14ec71411;hp=6d220071bacd4f1f540da7ca2b2791fc6118a0f9;hpb=f0ad1f3333cad2f943635f94182a632d291f765d;p=netconf.git diff --git a/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/get/AbstractGet.java b/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/get/AbstractGet.java index 6d220071ba..c323069e12 100644 --- a/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/get/AbstractGet.java +++ b/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/get/AbstractGet.java @@ -5,184 +5,173 @@ * 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.get; +import static com.google.common.base.Preconditions.checkArgument; + import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Throwables; -import com.google.common.collect.Iterables; import java.io.IOException; +import java.util.Optional; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.dom.DOMResult; -import org.opendaylight.controller.config.util.xml.DocumentedException; -import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity; -import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag; -import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType; -import org.opendaylight.controller.config.util.xml.XmlElement; +import org.opendaylight.netconf.api.DocumentedException; +import org.opendaylight.netconf.api.xml.XmlElement; import org.opendaylight.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.netconf.mdsal.connector.CurrentSchemaContext; import org.opendaylight.netconf.mdsal.connector.ops.Datastore; import org.opendaylight.netconf.util.mapping.AbstractSingletonNetconfOperation; -import org.opendaylight.yangtools.yang.common.QName; +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.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter; -import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter; -import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.opendaylight.yangtools.yang.data.api.schema.stream.YangInstanceIdentifierWriter; +import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; +// FIXME: seal when we have JDK17+ public abstract class AbstractGet extends AbstractSingletonNetconfOperation { + private static final XMLOutputFactory XML_OUTPUT_FACTORY; + private static final String FILTER = "filter"; - private static final Logger LOG = LoggerFactory.getLogger(AbstractGet.class); + static { + XML_OUTPUT_FACTORY = XMLOutputFactory.newFactory(); + XML_OUTPUT_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true); + } - protected static final String FILTER = "filter"; - static final YangInstanceIdentifier ROOT = YangInstanceIdentifier.builder().build(); + // FIXME: hide this field protected final CurrentSchemaContext schemaContext; private final FilterContentValidator validator; - public AbstractGet(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext) { + // FIXME: package-private + protected AbstractGet(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext) { super(netconfSessionIdForReporting); this.schemaContext = schemaContext; - this.validator = new FilterContentValidator(schemaContext); + validator = new FilterContentValidator(schemaContext); } - private static final XMLOutputFactory XML_OUTPUT_FACTORY; - - static { - XML_OUTPUT_FACTORY = XMLOutputFactory.newFactory(); - XML_OUTPUT_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true); - } - - protected Node transformNormalizedNode(final Document document, final NormalizedNode data, final YangInstanceIdentifier dataRoot) { - + // FIXME: hide this method + // FIXME: throw a DocumentedException + protected Node transformNormalizedNode(final Document document, final NormalizedNode data, + final YangInstanceIdentifier dataRoot) { final DOMResult result = new DOMResult(document.createElement(XmlNetconfConstants.DATA_KEY)); - final XMLStreamWriter xmlWriter = getXmlStreamWriter(result); + final EffectiveModelContext currentContext = schemaContext.getCurrentContext(); final NormalizedNodeStreamWriter nnStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter, - schemaContext.getCurrentContext(), getSchemaPath(dataRoot)); + currentContext); - final NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(nnStreamWriter, true); + try { + if (dataRoot.isEmpty()) { + writeRoot(nnStreamWriter, data); + } else { + write(nnStreamWriter, currentContext, dataRoot.coerceParent(), data); + } + } catch (IOException e) { + throw new RuntimeException(e); + } - writeRootElement(xmlWriter, nnWriter, (ContainerNode) data); return result.getNode(); } - - private XMLStreamWriter getXmlStreamWriter(final DOMResult result) { - try { - return XML_OUTPUT_FACTORY.createXMLStreamWriter(result); - } catch (final XMLStreamException e) { - throw new RuntimeException(e); + private static void write(final NormalizedNodeStreamWriter nnStreamWriter, + final EffectiveModelContext currentContext, final YangInstanceIdentifier parent, final NormalizedNode data) + throws IOException { + try (var yiidWriter = YangInstanceIdentifierWriter.open(nnStreamWriter, currentContext, parent)) { + try (var nnWriter = NormalizedNodeWriter.forStreamWriter(nnStreamWriter, true)) { + nnWriter.write(data); + } } } - private static final Function PATH_ARG_TO_QNAME = new Function() { - @Override - public QName apply(final YangInstanceIdentifier.PathArgument input) { - return input.getNodeType(); - } - }; + private static void writeRoot(final NormalizedNodeStreamWriter nnStreamWriter, final NormalizedNode data) + throws IOException { + checkArgument(data instanceof ContainerNode, "Unexpected root data %s", data); - private SchemaPath getSchemaPath(final YangInstanceIdentifier dataRoot) { - return SchemaPath.create(Iterables.transform(dataRoot.getPathArguments(), PATH_ARG_TO_QNAME), dataRoot.equals(ROOT)); + try (var nnWriter = NormalizedNodeWriter.forStreamWriter(nnStreamWriter, true)) { + for (var child : ((ContainerNode) data).body()) { + nnWriter.write(child); + } + } } - // TODO this code is located in Restconf already - private void writeRootElement(final XMLStreamWriter xmlWriter, final NormalizedNodeWriter nnWriter, final ContainerNode data) { + private static XMLStreamWriter getXmlStreamWriter(final DOMResult result) { try { - if (data.getNodeType().equals(SchemaContext.NAME)) { - for (final DataContainerChild child : data.getValue()) { - nnWriter.write(child); - } - } else { - nnWriter.write(data); - } - nnWriter.flush(); - xmlWriter.flush(); - } catch (XMLStreamException | IOException e) { - Throwables.propagate(e); + return XML_OUTPUT_FACTORY.createXMLStreamWriter(result); + } catch (final XMLStreamException e) { + throw new RuntimeException(e); } } - protected Element serializeNodeWithParentStructure(Document document, YangInstanceIdentifier dataRoot, NormalizedNode node) { - if (!dataRoot.equals(ROOT)) { - return (Element) transformNormalizedNode(document, - ImmutableNodes.fromInstanceId(schemaContext.getCurrentContext(), dataRoot, node), - ROOT); - } - return (Element) transformNormalizedNode(document, node, ROOT); + protected Element serializeNodeWithParentStructure(final Document document, final YangInstanceIdentifier dataRoot, + final NormalizedNode node) { + return (Element) transformNormalizedNode(document, node, dataRoot); } /** + * Obtain data root according to filter from operation element. * * @param operationElement operation element - * @return if Filter is present and not empty returns Optional of the InstanceIdentifier to the read location in datastore. - * empty filter returns Optional.absent() which should equal an empty <data/> container in the response. - * if filter is not present we want to read the entire datastore - return ROOT. - * @throws DocumentedException + * @return if filter is present and not empty returns Optional of the InstanceIdentifier to the read location + * in datastore. Empty filter returns Optional.absent() which should equal an empty <data/> + * container in the response. If filter is not present we want to read the entire datastore - return ROOT. + * @throws DocumentedException if not possible to get identifier from filter */ - protected Optional getDataRootFromFilter(XmlElement operationElement) throws DocumentedException { - Optional filterElement = operationElement.getOnlyChildElementOptionally(FILTER); + protected Optional getDataRootFromFilter(final XmlElement operationElement) + throws DocumentedException { + final Optional filterElement = operationElement.getOnlyChildElementOptionally(FILTER); if (filterElement.isPresent()) { if (filterElement.get().getChildElements().size() == 0) { - return Optional.absent(); + return Optional.empty(); } return Optional.of(getInstanceIdentifierFromFilter(filterElement.get())); - } else { - return Optional.of(ROOT); } + + return Optional.of(YangInstanceIdentifier.empty()); } @VisibleForTesting - protected YangInstanceIdentifier getInstanceIdentifierFromFilter(XmlElement filterElement) throws DocumentedException { + protected YangInstanceIdentifier getInstanceIdentifierFromFilter(final XmlElement filterElement) + throws DocumentedException { if (filterElement.getChildElements().size() != 1) { throw new DocumentedException("Multiple filter roots not supported yet", - ErrorType.application, ErrorTag.operation_not_supported, ErrorSeverity.error); + ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED, ErrorSeverity.ERROR); } - XmlElement element = filterElement.getOnlyChildElement(); + final XmlElement element = filterElement.getOnlyChildElement(); return validator.validate(element); } protected static final class GetConfigExecution { - private final Optional datastore; - public GetConfigExecution(final Optional datastore) { - this.datastore = datastore; - } - public Optional getDatastore() { - return datastore; + GetConfigExecution(final Optional datastore) { + this.datastore = datastore; } static GetConfigExecution fromXml(final XmlElement xml, final String operationName) throws DocumentedException { try { validateInputRpc(xml, operationName); } catch (final DocumentedException e) { - throw new DocumentedException("Incorrect RPC: " + e.getMessage(), e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo()); + throw new DocumentedException("Incorrect RPC: " + e.getMessage(), e, e.getErrorType(), e.getErrorTag(), + e.getErrorSeverity(), e.getErrorInfo()); } final Optional sourceDatastore; try { sourceDatastore = parseSource(xml); } catch (final DocumentedException e) { - throw new DocumentedException("Get-config source attribute error: " + e.getMessage(), e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo()); + throw new DocumentedException("Get-config source attribute error: " + e.getMessage(), e, + e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo()); } return new GetConfigExecution(sourceDatastore); @@ -191,16 +180,19 @@ public abstract class AbstractGet extends AbstractSingletonNetconfOperation { private static Optional parseSource(final XmlElement xml) throws DocumentedException { final Optional sourceElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SOURCE_KEY, XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0); - - return sourceElement.isPresent() ? - Optional.of(Datastore.valueOf(sourceElement.get().getOnlyChildElement().getName())) : Optional.absent(); + return sourceElement.isPresent() + ? Optional.of(Datastore.valueOf(sourceElement.get().getOnlyChildElement().getName())) + : Optional.empty(); } - private static void validateInputRpc(final XmlElement xml, String operationName) throws DocumentedException{ + private static void validateInputRpc(final XmlElement xml, final String operationName) throws + DocumentedException { xml.checkName(operationName); xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0); } + public Optional getDatastore() { + return datastore; + } } - }