From: Tomas Cere Date: Mon, 2 Mar 2015 09:50:47 +0000 (+0100) Subject: BUG 2743 - Added support for runtime RPC's to netconf mdsal northbound. X-Git-Tag: release/lithium~332^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=3b78a463e85c496cba2a68eddb027d9432b8d530 BUG 2743 - Added support for runtime RPC's to netconf mdsal northbound. Change-Id: I7f978502926c47535efc074a0522f6cfc0a3c3a5 Signed-off-by: Tomas Cere --- diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/mapper/NetconfMdsalMapperModule.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/mapper/NetconfMdsalMapperModule.java index bf8bdb06f3..bf41f190e6 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/mapper/NetconfMdsalMapperModule.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/mapper/NetconfMdsalMapperModule.java @@ -10,7 +10,7 @@ package org.opendaylight.controller.config.yang.netconf.mdsal.mapper; import org.opendaylight.controller.netconf.mdsal.connector.MdsalNetconfOperationServiceFactory; -public class NetconfMdsalMapperModule extends org.opendaylight.controller.config.yang.netconf.mdsal.mapper.AbstractNetconfMdsalMapperModule { +public class NetconfMdsalMapperModule extends org.opendaylight.controller.config.yang.netconf.mdsal.mapper.AbstractNetconfMdsalMapperModule{ public NetconfMdsalMapperModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { super(identifier, dependencyResolver); } @@ -26,13 +26,15 @@ public class NetconfMdsalMapperModule extends org.opendaylight.controller.config @Override public java.lang.AutoCloseable createInstance() { - final MdsalNetconfOperationServiceFactory mdsalNetconfOperationServiceFactory = new MdsalNetconfOperationServiceFactory(getRootSchemaServiceDependency(), getDomBrokerDependency()) { - @Override - public void close() throws Exception { - super.close(); - getMapperAggregatorDependency().onRemoveNetconfOperationServiceFactory(this); - } - }; + final MdsalNetconfOperationServiceFactory mdsalNetconfOperationServiceFactory = + new MdsalNetconfOperationServiceFactory(getRootSchemaServiceDependency()) { + @Override + public void close() throws Exception { + super.close(); + getMapperAggregatorDependency().onRemoveNetconfOperationServiceFactory(this); + } + }; + getDomBrokerDependency().registerConsumer(mdsalNetconfOperationServiceFactory); getMapperAggregatorDependency().onAddNetconfOperationServiceFactory(mdsalNetconfOperationServiceFactory); return mdsalNetconfOperationServiceFactory; } diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationService.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationService.java index cc22dd51aa..2f5bb098f5 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationService.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationService.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.mdsal.connector; import java.util.Set; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; import org.opendaylight.controller.netconf.mapping.api.NetconfOperation; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService; @@ -18,8 +19,8 @@ public class MdsalNetconfOperationService implements NetconfOperationService { private final OperationProvider operationProvider; public MdsalNetconfOperationService(final CurrentSchemaContext schemaContext, final String netconfSessionIdForReporting, - final DOMDataBroker dataBroker) { - this.operationProvider = new OperationProvider(netconfSessionIdForReporting, schemaContext, dataBroker); + final DOMDataBroker dataBroker, final DOMRpcService rpcService) { + this.operationProvider = new OperationProvider(netconfSessionIdForReporting, schemaContext, dataBroker, rpcService); } @Override diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationServiceFactory.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationServiceFactory.java index 89ce149e12..4086d2afec 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationServiceFactory.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationServiceFactory.java @@ -9,35 +9,42 @@ package org.opendaylight.controller.netconf.mdsal.connector; import com.google.common.base.Preconditions; +import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; import org.opendaylight.controller.netconf.api.Capability; import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory; import org.opendaylight.controller.netconf.util.capability.BasicCapability; import org.opendaylight.controller.netconf.util.capability.YangModuleCapability; +import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; +import org.opendaylight.controller.sal.core.api.Consumer; import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class MdsalNetconfOperationServiceFactory implements NetconfOperationServiceFactory, AutoCloseable { +public class MdsalNetconfOperationServiceFactory implements NetconfOperationServiceFactory, Consumer, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(MdsalNetconfOperationServiceFactory.class); - private final DOMDataBroker dataBroker; + private ConsumerSession session = null; + private DOMDataBroker dataBroker = null; + private DOMRpcService rpcService = null; private final CurrentSchemaContext currentSchemaContext; - public MdsalNetconfOperationServiceFactory(final SchemaService schemaService, final DOMDataBroker domDataBroker) { + public MdsalNetconfOperationServiceFactory(final SchemaService schemaService) { this.currentSchemaContext = new CurrentSchemaContext(Preconditions.checkNotNull(schemaService)); - this.dataBroker = Preconditions.checkNotNull(domDataBroker); } @Override public MdsalNetconfOperationService createService(final String netconfSessionIdForReporting) { - return new MdsalNetconfOperationService(currentSchemaContext, netconfSessionIdForReporting, dataBroker); + Preconditions.checkState(dataBroker != null, "MD-SAL provider not yet initialized"); + return new MdsalNetconfOperationService(currentSchemaContext, netconfSessionIdForReporting, dataBroker, rpcService); } @Override @@ -74,4 +81,15 @@ public class MdsalNetconfOperationServiceFactory implements NetconfOperationServ return currentSchemaContext.registerCapabilityListener(listener); } + @Override + public void onSessionInitiated(ConsumerSession session) { + this.session = Preconditions.checkNotNull(session); + this.dataBroker = this.session.getService(DOMDataBroker.class); + this.rpcService = this.session.getService(DOMRpcService.class); + } + + @Override + public Collection getConsumerFunctionality() { + return Collections.emptySet(); + } } diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/OperationProvider.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/OperationProvider.java index c881ae2e4e..8403dccc72 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/OperationProvider.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/OperationProvider.java @@ -11,11 +11,13 @@ package org.opendaylight.controller.netconf.mdsal.connector; import com.google.common.collect.Sets; import java.util.Set; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; import org.opendaylight.controller.netconf.mapping.api.NetconfOperation; import org.opendaylight.controller.netconf.mdsal.connector.ops.Commit; import org.opendaylight.controller.netconf.mdsal.connector.ops.DiscardChanges; import org.opendaylight.controller.netconf.mdsal.connector.ops.EditConfig; import org.opendaylight.controller.netconf.mdsal.connector.ops.Lock; +import org.opendaylight.controller.netconf.mdsal.connector.ops.RuntimeRpc; import org.opendaylight.controller.netconf.mdsal.connector.ops.Unlock; import org.opendaylight.controller.netconf.mdsal.connector.ops.get.Get; import org.opendaylight.controller.netconf.mdsal.connector.ops.get.GetConfig; @@ -25,14 +27,16 @@ final class OperationProvider { private final String netconfSessionIdForReporting; private final CurrentSchemaContext schemaContext; private final DOMDataBroker dataBroker; + private final DOMRpcService rpcService; private final TransactionProvider transactionProvider; - public OperationProvider(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext, final DOMDataBroker dataBroker) { + public OperationProvider(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext, + final DOMDataBroker dataBroker, final DOMRpcService rpcService) { this.netconfSessionIdForReporting = netconfSessionIdForReporting; this.schemaContext = schemaContext; this.dataBroker = dataBroker; - this.transactionProvider = new TransactionProvider(dataBroker, netconfSessionIdForReporting); - + this.rpcService = rpcService; + this.transactionProvider = new TransactionProvider(this.dataBroker, netconfSessionIdForReporting); } Set getOperations() { @@ -43,7 +47,8 @@ final class OperationProvider { new Get(netconfSessionIdForReporting, schemaContext, transactionProvider), new GetConfig(netconfSessionIdForReporting, schemaContext, transactionProvider), new Lock(netconfSessionIdForReporting), - new Unlock(netconfSessionIdForReporting) + new Unlock(netconfSessionIdForReporting), + new RuntimeRpc(netconfSessionIdForReporting, schemaContext, rpcService) ); } diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Commit.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Commit.java index 5a980c44d3..47e8f80585 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Commit.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Commit.java @@ -12,7 +12,7 @@ import com.google.common.base.Optional; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider; -import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation; +import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.slf4j.Logger; @@ -20,7 +20,7 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -public class Commit extends AbstractLastNetconfOperation{ +public class Commit extends AbstractSingletonNetconfOperation { private static final Logger LOG = LoggerFactory.getLogger(Commit.class); diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/DiscardChanges.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/DiscardChanges.java index b47bb18434..ce4de18ee6 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/DiscardChanges.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/DiscardChanges.java @@ -17,7 +17,7 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorT import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType; import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider; -import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation; +import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.slf4j.Logger; @@ -25,7 +25,7 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -public class DiscardChanges extends AbstractLastNetconfOperation{ +public class DiscardChanges extends AbstractSingletonNetconfOperation { private static final Logger LOG = LoggerFactory.getLogger(DiscardChanges.class); @@ -59,4 +59,5 @@ public class DiscardChanges extends AbstractLastNetconfOperation{ protected String getOperationName() { return OPERATION_NAME; } + } diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java index aebdfd9baf..fbefb5c56d 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java @@ -25,7 +25,7 @@ import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext; import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider; import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException; import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException; -import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation; +import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.opendaylight.yangtools.yang.data.api.ModifyAction; @@ -48,7 +48,7 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -public class EditConfig extends AbstractLastNetconfOperation { +public class EditConfig extends AbstractSingletonNetconfOperation { private static final Logger LOG = LoggerFactory.getLogger(EditConfig.class); @@ -229,4 +229,5 @@ public class EditConfig extends AbstractLastNetconfOperation { protected String getOperationName() { return OPERATION_NAME; } + } diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Lock.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Lock.java index db912c5fc0..ef94f69f7a 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Lock.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Lock.java @@ -13,7 +13,7 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException; import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException; -import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation; +import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.slf4j.Logger; @@ -21,7 +21,7 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -public class Lock extends AbstractLastNetconfOperation{ +public class Lock extends AbstractSingletonNetconfOperation { private static final Logger LOG = LoggerFactory.getLogger(Lock.class); @@ -61,4 +61,5 @@ public class Lock extends AbstractLastNetconfOperation{ protected String getOperationName() { return OPERATION_NAME; } + } diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/RuntimeRpc.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/RuntimeRpc.java new file mode 100644 index 0000000000..ff7d30d574 --- /dev/null +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/RuntimeRpc.java @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * 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.controller.netconf.mdsal.connector.ops; + +import com.google.common.base.Optional; +import com.google.common.base.Throwables; +import com.google.common.util.concurrent.CheckedFuture; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.Map; +import javax.annotation.Nullable; +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.md.sal.dom.api.DOMRpcException; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType; +import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; +import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution; +import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext; +import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException; +import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +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.transform.dom.DomUtils; +import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.RpcDefinition; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class RuntimeRpc extends AbstractSingletonNetconfOperation { + + private static final Logger LOG = LoggerFactory.getLogger(RuntimeRpc.class); + + private final CurrentSchemaContext schemaContext; + private static final XMLOutputFactory XML_OUTPUT_FACTORY; + + static { + XML_OUTPUT_FACTORY = XMLOutputFactory.newFactory(); + XML_OUTPUT_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true); + } + + private final DOMRpcService rpcService; + + public RuntimeRpc(final String netconfSessionIdForReporting, CurrentSchemaContext schemaContext, DOMRpcService rpcService) { + super(netconfSessionIdForReporting); + this.schemaContext = schemaContext; + this.rpcService = rpcService; + } + + @Override + protected HandlingPriority canHandle(final String netconfOperationName, final String namespace) { + final URI namespaceURI = createNsUri(namespace); + final Optional module = getModule(namespaceURI); + + if (!module.isPresent()) { + LOG.debug("Cannot handle rpc: {}, {}", netconfOperationName, namespace); + return HandlingPriority.CANNOT_HANDLE; + } + + getRpcDefinitionFromModule(module.get(), namespaceURI, netconfOperationName); + return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY; + + } + + @Override + protected String getOperationName() { + throw new UnsupportedOperationException("Runtime rpc does not have a stable name"); + } + + private URI createNsUri(final String namespace) { + final URI namespaceURI; + try { + namespaceURI = new URI(namespace); + } catch (URISyntaxException e) { + // Cannot occur, namespace in parsed XML cannot be invalid URI + throw new IllegalStateException("Unable to parse URI " + namespace, e); + } + return namespaceURI; + } + + //this returns module with the newest revision if more then 1 module with same namespace is found + private Optional getModule(final URI namespaceURI) { + return Optional.of(schemaContext.getCurrentContext().findModuleByNamespaceAndRevision(namespaceURI, null)); + } + + private Optional getRpcDefinitionFromModule(Module module, URI namespaceURI, String name) { + for (RpcDefinition rpcDef : module.getRpcs()) { + if (rpcDef.getQName().getNamespace().equals(namespaceURI) + && rpcDef.getQName().getLocalName().equals(name)) { + return Optional.of(rpcDef); + } + } + return Optional.absent(); + } + + @Override + protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException { + + final String netconfOperationName = operationElement.getName(); + final String netconfOperationNamespace; + try { + netconfOperationNamespace = operationElement.getNamespace(); + } catch (MissingNameSpaceException e) { + LOG.debug("Cannot retrieve netconf operation namespace from message due to ", e); + throw new NetconfDocumentedException("Cannot retrieve netconf operation namespace from message", + ErrorType.protocol, ErrorTag.unknown_namespace, ErrorSeverity.error); + } + + final URI namespaceURI = createNsUri(netconfOperationNamespace); + final Optional moduleOptional = getModule(namespaceURI); + + if (!moduleOptional.isPresent()) { + throw new NetconfDocumentedException("Unable to find module in Schema Context with namespace and name : " + + namespaceURI + " " + netconfOperationName + schemaContext.getCurrentContext(), + ErrorType.application, ErrorTag.bad_element, ErrorSeverity.error); + } + + final Optional rpcDefinitionOptional = getRpcDefinitionFromModule(moduleOptional.get(), namespaceURI, netconfOperationName); + + if (!rpcDefinitionOptional.isPresent()) { + throw new NetconfDocumentedException("Unable to find RpcDefinition with namespace and name : " + namespaceURI + " " + netconfOperationName, + ErrorType.application, ErrorTag.bad_element, ErrorSeverity.error); + } + + final RpcDefinition rpcDefinition = rpcDefinitionOptional.get(); + final SchemaPath schemaPath = SchemaPath.create(Collections.singletonList(rpcDefinition.getQName()), true); + final NormalizedNode inputNode = rpcToNNode(operationElement, rpcDefinition.getInput()); + + final CheckedFuture rpcFuture = rpcService.invokeRpc(schemaPath, inputNode); + try { + final DOMRpcResult result = rpcFuture.checkedGet(); + if (result.getResult() == null) { + return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.of(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0)); + } + return (Element) transformNormalizedNode(document, result.getResult(), rpcDefinition.getOutput().getPath()); + } catch (DOMRpcException e) { + throw NetconfDocumentedException.wrap(e); + } + } + + @Override + public Document handle(final Document requestMessage, + final NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException { + + final XmlElement requestElement = getRequestElementWithCheck(requestMessage); + + final Document document = XmlUtil.newDocument(); + + final XmlElement operationElement = requestElement.getOnlyChildElement(); + final Map attributes = requestElement.getAttributes(); + + final Element response = handle(document, operationElement, subsequentOperation); + final Element rpcReply = XmlUtil.createElement(document, XmlNetconfConstants.RPC_REPLY_KEY, Optional.of(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0)); + + if(XmlElement.fromDomElement(response).hasNamespace()) { + rpcReply.appendChild(response); + } else { + final NodeList list = response.getChildNodes(); + if (list.getLength() == 0) { + rpcReply.appendChild(response); + } else { + while (list.getLength() != 0) { + rpcReply.appendChild(list.item(0)); + } + } + } + + for (Attr attribute : attributes.values()) { + rpcReply.setAttributeNode((Attr) document.importNode(attribute, true)); + } + document.appendChild(rpcReply); + return document; + } + + //TODO move all occurences of this method in mdsal netconf(and xml factories) to a utility class + private Node transformNormalizedNode(final Document document, final NormalizedNode data, final SchemaPath rpcOutputPath) { + final DOMResult result = new DOMResult(document.createElement(XmlNetconfConstants.RPC_REPLY_KEY)); + + final XMLStreamWriter xmlWriter = getXmlStreamWriter(result); + + final NormalizedNodeStreamWriter nnStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter, + schemaContext.getCurrentContext(), rpcOutputPath); + + final NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(nnStreamWriter); + + writeRootElement(xmlWriter, nnWriter, (ContainerNode) data); + try { + nnStreamWriter.close(); + xmlWriter.close(); + } catch (IOException | XMLStreamException e) { + LOG.warn("Error while closing streams", e); + } + + 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 void writeRootElement(final XMLStreamWriter xmlWriter, final NormalizedNodeWriter nnWriter, final ContainerNode data) { + try { + for (final DataContainerChild child : data.getValue()) { + nnWriter.write(child); + } + nnWriter.flush(); + xmlWriter.flush(); + } catch (XMLStreamException | IOException e) { + Throwables.propagate(e); + } + } + + /** + * Parses xml element rpc input into normalized node or null if rpc does not take any input + * @param oElement rpc xml element + * @param input input container schema node, or null if rpc does not take any input + * @return parsed rpc into normalized node, or null if input schema is null + */ + @Nullable + private NormalizedNode rpcToNNode(final XmlElement oElement, @Nullable final ContainerSchemaNode input) { + return input == null ? null : DomToNormalizedNodeParserFactory + .getInstance(DomUtils.defaultValueCodecProvider(), schemaContext.getCurrentContext()) + .getContainerNodeParser() + .parse(Collections.singletonList(oElement.getDomElement()), input); + } + +} diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Unlock.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Unlock.java index 2dd26633dd..08ffe8b2a0 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Unlock.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Unlock.java @@ -11,7 +11,7 @@ package org.opendaylight.controller.netconf.mdsal.connector.ops; import com.google.common.base.Optional; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; -import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation; +import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.slf4j.Logger; @@ -19,7 +19,7 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -public class Unlock extends AbstractLastNetconfOperation{ +public class Unlock extends AbstractSingletonNetconfOperation { private static final Logger LOG = LoggerFactory.getLogger(Unlock.class); diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/AbstractGet.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/AbstractGet.java index 711cb8145b..9a66ceb5bc 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/AbstractGet.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/AbstractGet.java @@ -29,7 +29,7 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorT import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext; import org.opendaylight.controller.netconf.mdsal.connector.ops.Datastore; -import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation; +import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.sal.connect.netconf.util.InstanceIdToNodes; import org.opendaylight.yangtools.yang.common.QName; @@ -56,7 +56,7 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; -public abstract class AbstractGet extends AbstractLastNetconfOperation { +public abstract class AbstractGet extends AbstractSingletonNetconfOperation { private static final Logger LOG = LoggerFactory.getLogger(AbstractGet.class); diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/yang/netconf-mdsal-mapper.yang b/opendaylight/netconf/mdsal-netconf-connector/src/main/yang/netconf-mdsal-mapper.yang index 9d9966e8f1..c787287da5 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/yang/netconf-mdsal-mapper.yang +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/yang/netconf-mdsal-mapper.yang @@ -39,8 +39,8 @@ module netconf-mdsal-mapper { container dom-broker { uses config:service-ref { refine type { - mandatory false; - config:required-identity md-sal-dom:dom-async-data-broker; + mandatory true; + config:required-identity md-sal-dom:dom-broker-osgi-registry; } } } diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/test/java/org/opendaylight/controller/netconf/mdsal/connector/ops/RuntimeRpcTest.java b/opendaylight/netconf/mdsal-netconf-connector/src/test/java/org/opendaylight/controller/netconf/mdsal/connector/ops/RuntimeRpcTest.java new file mode 100644 index 0000000000..32eb08c2e7 --- /dev/null +++ b/opendaylight/netconf/mdsal-netconf-connector/src/test/java/org/opendaylight/controller/netconf/mdsal/connector/ops/RuntimeRpcTest.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * 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.controller.netconf.mdsal.connector.ops; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Preconditions; +import com.google.common.io.ByteSource; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.custommonkey.xmlunit.DetailedDiff; +import org.custommonkey.xmlunit.Diff; +import org.custommonkey.xmlunit.XMLUnit; +import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcException; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; +import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType; +import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution; +import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext; +import org.opendaylight.controller.netconf.util.test.XmlFileLoader; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +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.impl.schema.builder.impl.ImmutableContainerNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.RpcDefinition; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException; +import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils; +import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; + +public class RuntimeRpcTest { + + private static final Logger LOG = LoggerFactory.getLogger(RuntimeRpcTest.class); + + private String sessionIdForReporting = "netconf-test-session1"; + + private static Document RPC_REPLY_OK = null; + + static { + try { + RPC_REPLY_OK = XmlFileLoader.xmlFileToDocument("messages/mapping/rpcs/runtimerpc-ok-reply.xml"); + } catch (Exception e) { + LOG.debug("unable to load rpc reply ok.", e); + RPC_REPLY_OK = XmlUtil.newDocument(); + } + } + + private DOMRpcService rpcServiceVoidInvoke = new DOMRpcService() { + @Nonnull + @Override + public CheckedFuture invokeRpc(@Nonnull SchemaPath type, @Nullable NormalizedNode input) { + return Futures.immediateCheckedFuture((DOMRpcResult) new DefaultDOMRpcResult(null, Collections.emptyList())); + } + + @Nonnull + @Override + public ListenerRegistration registerRpcListener(@Nonnull T listener) { + return null; + } + }; + + private DOMRpcService rpcServiceFailedInvocation = new DOMRpcService() { + @Nonnull + @Override + public CheckedFuture invokeRpc(@Nonnull SchemaPath type, @Nullable NormalizedNode input) { + return Futures.immediateFailedCheckedFuture((DOMRpcException) new DOMRpcException("rpc invocation not implemented yet") { + }); + } + + @Nonnull + @Override + public ListenerRegistration registerRpcListener(@Nonnull T listener) { + return null; + } + }; + + private DOMRpcService rpcServiceSuccesfullInvocation = new DOMRpcService() { + @Nonnull + @Override + public CheckedFuture invokeRpc(@Nonnull SchemaPath type, @Nullable NormalizedNode input) { + Collection> children = (Collection) input.getValue(); + Module module = schemaContext.findModuleByNamespaceAndRevision(type.getLastComponent().getNamespace(), null); + RpcDefinition rpcDefinition = getRpcDefinitionFromModule(module, module.getNamespace(), type.getLastComponent().getLocalName()); + ContainerSchemaNode outputSchemaNode = rpcDefinition.getOutput(); + ContainerNode node = ImmutableContainerNodeBuilder.create() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(outputSchemaNode.getQName())) + .withValue(children).build(); + + return Futures.immediateCheckedFuture((DOMRpcResult) new DefaultDOMRpcResult(node)); + } + + @Nonnull + @Override + public ListenerRegistration registerRpcListener(@Nonnull T listener) { + return null; + } + }; + + private SchemaContext schemaContext = null; + private CurrentSchemaContext currentSchemaContext = null; + @Mock + private SchemaService schemaService; + @Mock + private SchemaContextListener listener; + @Mock + private ListenerRegistration registration; + + @Before + public void setUp() throws Exception { + + initMocks(this); + doNothing().when(registration).close(); + doReturn(listener).when(registration).getInstance(); + doNothing().when(schemaService).addModule(any(Module.class)); + doNothing().when(schemaService).removeModule(any(Module.class)); + doReturn(schemaContext).when(schemaService).getGlobalContext(); + doReturn(schemaContext).when(schemaService).getSessionContext(); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + ((SchemaContextListener) invocationOnMock.getArguments()[0]).onGlobalContextUpdated(schemaContext); + return registration; + } + }).when(schemaService).registerSchemaContextListener(any(SchemaContextListener.class)); + + XMLUnit.setIgnoreWhitespace(true); + XMLUnit.setIgnoreAttributeOrder(true); + + this.schemaContext = parseSchemas(getYangSchemas()); + this.currentSchemaContext = new CurrentSchemaContext(schemaService); + } + + @Test + public void testVoidOutputRpc() throws Exception { + RuntimeRpc rpc = new RuntimeRpc(sessionIdForReporting, currentSchemaContext, rpcServiceVoidInvoke); + + Document rpcDocument = XmlFileLoader.xmlFileToDocument("messages/mapping/rpcs/rpc-void-output.xml"); + HandlingPriority priority = rpc.canHandle(rpcDocument); + Preconditions.checkState(priority != HandlingPriority.CANNOT_HANDLE); + + Document response = rpc.handle(rpcDocument, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT); + + verifyResponse(response, RPC_REPLY_OK); + } + + @Test + public void testSuccesfullNonVoidInvocation() throws Exception { + RuntimeRpc rpc = new RuntimeRpc(sessionIdForReporting, currentSchemaContext, rpcServiceSuccesfullInvocation); + + Document rpcDocument = XmlFileLoader.xmlFileToDocument("messages/mapping/rpcs/rpc-nonvoid.xml"); + HandlingPriority priority = rpc.canHandle(rpcDocument); + Preconditions.checkState(priority != HandlingPriority.CANNOT_HANDLE); + + Document response = rpc.handle(rpcDocument, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT); + verifyResponse(response, XmlFileLoader.xmlFileToDocument("messages/mapping/rpcs/rpc-nonvoid-control.xml")); + } + + @Test + public void testFailedInvocation() throws Exception { + RuntimeRpc rpc = new RuntimeRpc(sessionIdForReporting, currentSchemaContext, rpcServiceFailedInvocation); + + Document rpcDocument = XmlFileLoader.xmlFileToDocument("messages/mapping/rpcs/rpc-nonvoid.xml"); + HandlingPriority priority = rpc.canHandle(rpcDocument); + Preconditions.checkState(priority != HandlingPriority.CANNOT_HANDLE); + + try { + rpc.handle(rpcDocument, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT); + fail("should have failed with rpc invocation not implemented yet"); + } catch (NetconfDocumentedException e) { + assertTrue(e.getErrorType() == ErrorType.application); + assertTrue(e.getErrorSeverity() == ErrorSeverity.error); + assertTrue(e.getErrorTag() == ErrorTag.operation_failed); + } + } + + @Test + public void testVoidInputOutputRpc() throws Exception { + RuntimeRpc rpc = new RuntimeRpc(sessionIdForReporting, currentSchemaContext, rpcServiceVoidInvoke); + + Document rpcDocument = XmlFileLoader.xmlFileToDocument("messages/mapping/rpcs/rpc-void-input-output.xml"); + HandlingPriority priority = rpc.canHandle(rpcDocument); + Preconditions.checkState(priority != HandlingPriority.CANNOT_HANDLE); + + Document response = rpc.handle(rpcDocument, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT); + + verifyResponse(response, RPC_REPLY_OK); + } + + private void verifyResponse(Document response, Document template) { + DetailedDiff dd = new DetailedDiff(new Diff(response, template)); + dd.overrideElementQualifier(new RecursiveElementNameAndTextQualifier()); + assertTrue(dd.similar()); + } + + private RpcDefinition getRpcDefinitionFromModule(Module module, URI namespaceURI, String name) { + for (RpcDefinition rpcDef : module.getRpcs()) { + if (rpcDef.getQName().getNamespace().equals(namespaceURI) + && rpcDef.getQName().getLocalName().equals(name)) { + return rpcDef; + } + } + + return null; + + } + + private Collection getYangSchemas() { + final List schemaPaths = Arrays.asList("/yang/mdsal-netconf-rpc-test.yang"); + final List schemas = new ArrayList<>(); + + for (String schemaPath : schemaPaths) { + InputStream resourceAsStream = getClass().getResourceAsStream(schemaPath); + schemas.add(resourceAsStream); + } + + return schemas; + } + + private SchemaContext parseSchemas(Collection schemas) throws IOException, YangSyntaxErrorException { + final YangParserImpl parser = new YangParserImpl(); + Collection sources = BuilderUtils.streamsToByteSources(schemas); + return parser.parseSources(sources); + } +} \ No newline at end of file diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/rpc-nonvoid-control.xml b/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/rpc-nonvoid-control.xml new file mode 100644 index 0000000000..139885b9f3 --- /dev/null +++ b/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/rpc-nonvoid-control.xml @@ -0,0 +1,17 @@ + + + + + test rpc input string 1 + + + test rpc input string 2 + + \ No newline at end of file diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/rpc-nonvoid.xml b/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/rpc-nonvoid.xml new file mode 100644 index 0000000000..b5cc5ecb40 --- /dev/null +++ b/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/rpc-nonvoid.xml @@ -0,0 +1,19 @@ + + + + + + test rpc input string 1 + + + test rpc input string 2 + + + \ No newline at end of file diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/rpc-void-input-output.xml b/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/rpc-void-input-output.xml new file mode 100644 index 0000000000..c6b09f86c9 --- /dev/null +++ b/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/rpc-void-input-output.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/rpc-void-output.xml b/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/rpc-void-output.xml new file mode 100644 index 0000000000..a963865257 --- /dev/null +++ b/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/rpc-void-output.xml @@ -0,0 +1,19 @@ + + + + + + test rpc input string 1 + + + test rpc input string 2 + + + \ No newline at end of file diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/runtimerpc-ok-reply.xml b/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/runtimerpc-ok-reply.xml new file mode 100644 index 0000000000..e44046eb4e --- /dev/null +++ b/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/rpcs/runtimerpc-ok-reply.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/yang/mdsal-netconf-rpc-test.yang b/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/yang/mdsal-netconf-rpc-test.yang new file mode 100644 index 0000000000..d493840828 --- /dev/null +++ b/opendaylight/netconf/mdsal-netconf-connector/src/test/resources/yang/mdsal-netconf-rpc-test.yang @@ -0,0 +1,44 @@ +module rpc-test { + yang-version 1; + namespace "urn:opendaylight:mdsal:mapping:rpc:test"; + prefix "rpc"; + + rpc void-input-output-rpc { + + } + + rpc void-output-rpc { + input { + leaf test-string { + type string; + } + + leaf test-string2 { + type string; + } + } + } + + rpc nonvoid-rpc { + input { + leaf test-string { + type string; + } + + leaf test-string2 { + type string; + } + } + + output { + leaf test-string { + type string; + } + + leaf test-string2 { + type string; + } + } + } +} + diff --git a/opendaylight/netconf/netconf-mdsal-config/src/main/resources/initial/08-netconf-mdsal.xml b/opendaylight/netconf/netconf-mdsal-config/src/main/resources/initial/08-netconf-mdsal.xml index 4ca3c99e81..1982615173 100644 --- a/opendaylight/netconf/netconf-mdsal-config/src/main/resources/initial/08-netconf-mdsal.xml +++ b/opendaylight/netconf/netconf-mdsal-config/src/main/resources/initial/08-netconf-mdsal.xml @@ -22,8 +22,8 @@ yang-schema-service - dom:dom-async-data-broker - inmemory-data-broker + dom:dom-broker-osgi-registry + dom-broker prefix:netconf-mapper-registry diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/GetSchema.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/GetSchema.java index d02cb432cb..961c9f57c2 100644 --- a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/GetSchema.java +++ b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/GetSchema.java @@ -15,7 +15,7 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService; import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException; -import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation; +import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.slf4j.Logger; @@ -23,7 +23,7 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -public class GetSchema extends AbstractLastNetconfOperation { +public class GetSchema extends AbstractSingletonNetconfOperation { public static final String GET_SCHEMA = "get-schema"; public static final String IDENTIFIER = "identifier"; public static final String VERSION = "version"; diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractSingletonNetconfOperation.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractSingletonNetconfOperation.java index 4491e763b3..3e64e93ed7 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractSingletonNetconfOperation.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractSingletonNetconfOperation.java @@ -7,7 +7,12 @@ */ package org.opendaylight.controller.netconf.util.mapping; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.w3c.dom.Document; +import org.w3c.dom.Element; public abstract class AbstractSingletonNetconfOperation extends AbstractLastNetconfOperation { @@ -15,6 +20,12 @@ public abstract class AbstractSingletonNetconfOperation extends AbstractLastNetc super(netconfSessionIdForReporting); } + @Override + protected Element handle(Document document, XmlElement operationElement, + NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException { + return handleWithNoSubsequentOperations(document, operationElement); + } + @Override protected HandlingPriority getHandlingPriority() { return HandlingPriority.HANDLE_WITH_MAX_PRIORITY;