From: Maros Marsalek Date: Thu, 11 Feb 2016 18:49:50 +0000 (+0000) Subject: Merge "Bug 2806 - Immediate and infinite reconnect attempts during negotiation" into... X-Git-Tag: release/beryllium~4 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=fdece89e1115f52dc6b65e8843fbbdacca2c67e7;hp=b3422815f769ea6ca5b95a2e9e174922d4fe5b93;p=netconf.git Merge "Bug 2806 - Immediate and infinite reconnect attempts during negotiation" into stable/beryllium --- diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/TransactionProvider.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/TransactionProvider.java index 1eacbf364b..0bcd7370fc 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/TransactionProvider.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/TransactionProvider.java @@ -83,11 +83,14 @@ public class TransactionProvider implements AutoCloseable{ future.checkedGet(); } catch (TransactionCommitFailedException e) { LOG.debug("Transaction {} failed on", candidateTransaction, e); - throw new DocumentedException("Transaction commit failed on " + e.getMessage() + " " + netconfSessionIdForReporting, + final String cause = e.getCause() != null ? (" Cause: " + e.getCause().getMessage()) : ""; + throw new DocumentedException("Transaction commit failed on " + e.getMessage() + " " + netconfSessionIdForReporting + + cause, ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error); + } finally { + allOpenReadWriteTransactions.remove(candidateTransaction); + candidateTransaction = null; } - allOpenReadWriteTransactions.remove(candidateTransaction); - candidateTransaction = null; return true; } diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/netconf/impl/osgi/AggregatedNetconfOperationServiceFactoryTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/netconf/impl/osgi/AggregatedNetconfOperationServiceFactoryTest.java new file mode 100644 index 0000000000..bf078e2200 --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/netconf/impl/osgi/AggregatedNetconfOperationServiceFactoryTest.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016 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.netconf.impl.osgi; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import com.google.common.collect.Sets; +import java.util.HashSet; +import java.util.Set; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.util.capability.BasicCapability; +import org.opendaylight.controller.config.util.capability.Capability; +import org.opendaylight.netconf.api.monitoring.CapabilityListener; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory; + + +public class AggregatedNetconfOperationServiceFactoryTest { + + private Set factory1Caps = new HashSet<>(); + private Set factory2Caps = new HashSet<>(); + + @Mock + private CapabilityListener listener1; + @Mock + private CapabilityListener listener2; + @Mock + private CapabilityListener listener3; + @Mock + private NetconfOperationServiceFactory factory1; + @Mock + private NetconfOperationServiceFactory factory2; + @Mock + private AutoCloseable autoCloseable1; + @Mock + private AutoCloseable autoCloseable2; + @Mock + private AutoCloseable autoCloseable3; + + private AggregatedNetconfOperationServiceFactory aggregatedFactory; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + factory1Caps.add(new BasicCapability("AAA")); + factory1Caps.add(new BasicCapability("BBB")); + + factory2Caps.add(new BasicCapability("CCC")); + factory2Caps.add(new BasicCapability("DDD")); + + aggregatedFactory = new AggregatedNetconfOperationServiceFactory(); + + aggregatedFactory.registerCapabilityListener(listener1); + aggregatedFactory.registerCapabilityListener(listener2); + + doReturn(autoCloseable1).when(factory1).registerCapabilityListener(listener1); + doReturn(autoCloseable2).when(factory1).registerCapabilityListener(listener2); + doReturn(factory1Caps).when(factory1).getCapabilities(); + + doReturn(autoCloseable1).when(factory2).registerCapabilityListener(listener1); + doReturn(autoCloseable2).when(factory2).registerCapabilityListener(listener2); + doReturn(factory2Caps).when(factory2).getCapabilities(); + + doNothing().when(autoCloseable1).close(); + doNothing().when(autoCloseable2).close(); + + doReturn(autoCloseable3).when(factory1).registerCapabilityListener(listener3); + doReturn(autoCloseable3).when(factory2).registerCapabilityListener(listener3); + } + + @Test + public void testOnAddAndOnRemove() throws Exception { + aggregatedFactory.onAddNetconfOperationServiceFactory(factory1); + aggregatedFactory.onAddNetconfOperationServiceFactory(factory2); + + verify(factory1).registerCapabilityListener(listener1); + verify(factory2).registerCapabilityListener(listener1); + verify(factory1).registerCapabilityListener(listener2); + verify(factory2).registerCapabilityListener(listener2); + + aggregatedFactory.onRemoveNetconfOperationServiceFactory(factory1); + aggregatedFactory.onRemoveNetconfOperationServiceFactory(factory2); + + verify(autoCloseable1, times(2)).close(); + verify(autoCloseable2, times(2)).close(); + } + + @Test + public void testGetCapabilities() throws Exception { + aggregatedFactory.onAddNetconfOperationServiceFactory(factory1); + aggregatedFactory.onAddNetconfOperationServiceFactory(factory2); + final Set actual = aggregatedFactory.getCapabilities(); + Set expected = Sets.union(factory1Caps, factory2Caps); + Assert.assertEquals(expected, actual); + } + + @Test + public void testRegisterCapabilityListener() throws Exception { + aggregatedFactory.onAddNetconfOperationServiceFactory(factory1); + aggregatedFactory.onAddNetconfOperationServiceFactory(factory2); + aggregatedFactory.registerCapabilityListener(listener3); + + verify(factory1).registerCapabilityListener(listener3); + verify(factory2).registerCapabilityListener(listener3); + } + + @Test + public void testClose() throws Exception { + aggregatedFactory.onAddNetconfOperationServiceFactory(factory1); + aggregatedFactory.onAddNetconfOperationServiceFactory(factory2); + aggregatedFactory.close(); + verify(autoCloseable1, times(2)).close(); + verify(autoCloseable2, times(2)).close(); + } + +} \ No newline at end of file diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/netconf/impl/osgi/NetconfMonitoringServiceImplTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/netconf/impl/osgi/NetconfMonitoringServiceImplTest.java new file mode 100644 index 0000000000..bfda1e0523 --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/netconf/impl/osgi/NetconfMonitoringServiceImplTest.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2016 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.netconf.impl.osgi; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; + +import com.google.common.base.Optional; +import java.net.URI; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.util.capability.BasicCapability; +import org.opendaylight.controller.config.util.capability.Capability; +import org.opendaylight.controller.config.util.capability.YangModuleCapability; +import org.opendaylight.netconf.api.monitoring.NetconfManagementSession; +import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory; +import org.opendaylight.netconf.notifications.BaseNotificationPublisherRegistration; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.CapabilitiesBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.SessionBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange; +import org.opendaylight.yangtools.yang.model.api.Module; + +public class NetconfMonitoringServiceImplTest { + + private static final String TEST_MODULE_CONTENT = "content"; + private static final String TEST_MODULE_REV = "1970-01-01"; + private static final Uri TEST_MODULE_NAMESPACE = new Uri("testModuleNamespace"); + private static final String TEST_MODULE_NAME = "testModule"; + private static final Date TEST_MODULE_DATE = new Date(0); + + private final Set CAPABILITIES = new HashSet<>(); + + private NetconfMonitoringServiceImpl monitoringService; + + @Mock + private Module moduleMock; + @Mock + private NetconfOperationServiceFactory operationServiceFactoryMock; + @Mock + private NetconfManagementSession sessionMock; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + CAPABILITIES.add(new BasicCapability("urn:ietf:params:netconf:base:1.0")); + CAPABILITIES.add(new BasicCapability("urn:ietf:params:netconf:base:1.1")); + CAPABILITIES.add(new BasicCapability("urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24")); + doReturn(new URI(TEST_MODULE_NAMESPACE.getValue())).when(moduleMock).getNamespace(); + doReturn(TEST_MODULE_NAME).when(moduleMock).getName(); + doReturn(TEST_MODULE_DATE).when(moduleMock).getRevision(); + doReturn(TEST_MODULE_NAME).when(moduleMock).getName(); + + CAPABILITIES.add(new YangModuleCapability(moduleMock, TEST_MODULE_CONTENT)); + doReturn(CAPABILITIES).when(operationServiceFactoryMock).getCapabilities(); + doReturn(null).when(operationServiceFactoryMock).registerCapabilityListener(any(NetconfMonitoringServiceImpl.class)); + + monitoringService = new NetconfMonitoringServiceImpl(operationServiceFactoryMock); + monitoringService.onCapabilitiesChanged(CAPABILITIES, new HashSet()); + + doReturn(new SessionBuilder().build()).when(sessionMock).toManagementSession(); + } + + @Test + public void testListeners() throws Exception { + final AtomicInteger stateChanged = new AtomicInteger(0); + NetconfMonitoringService.MonitoringListener listener = getMonitoringListener(stateChanged); + monitoringService.registerListener(listener); + Assert.assertEquals(1, stateChanged.get()); + monitoringService.onSessionUp(sessionMock); + Assert.assertEquals(2, stateChanged.get()); + HashSet added = new HashSet<>(); + added.add(new BasicCapability("toAdd")); + monitoringService.onCapabilitiesChanged(added, new HashSet()); + Assert.assertEquals(3, stateChanged.get()); + monitoringService.onSessionDown(sessionMock); + Assert.assertEquals(4, stateChanged.get()); + } + + @Test + public void testGetSchemas() throws Exception { + Schemas schemas = monitoringService.getSchemas(); + Schema schema = schemas.getSchema().get(0); + Assert.assertEquals(TEST_MODULE_NAMESPACE, schema.getNamespace()); + Assert.assertEquals(TEST_MODULE_NAME, schema.getIdentifier()); + Assert.assertEquals(TEST_MODULE_REV, schema.getVersion()); + + } + + @Test + public void testGetSchemaForCapability() throws Exception { + String schema = monitoringService.getSchemaForCapability(TEST_MODULE_NAME, Optional.of(TEST_MODULE_REV)); + Assert.assertEquals(TEST_MODULE_CONTENT, schema); + + } + + @Test + public void testGetCapabilities() throws Exception { + Capabilities actual = monitoringService.getCapabilities(); + List exp = new ArrayList<>(); + for (Capability capability : CAPABILITIES) { + exp.add(new Uri(capability.getCapabilityUri())); + } + exp.add(0, new Uri("urn:ietf:params:netconf:capability:candidate:1.0")); + Capabilities expected = new CapabilitiesBuilder().setCapability(exp).build(); + Assert.assertEquals(new HashSet<>(expected.getCapability()), new HashSet<>(actual.getCapability())); + } + + @Test + public void testClose() throws Exception { + monitoringService.onSessionUp(sessionMock); + Assert.assertFalse(monitoringService.getSessions().getSession().isEmpty()); + Assert.assertFalse(monitoringService.getCapabilities().getCapability().isEmpty()); + monitoringService.close(); + Assert.assertTrue(monitoringService.getSessions().getSession().isEmpty()); + Assert.assertTrue(monitoringService.getCapabilities().getCapability().isEmpty()); + } + + @Test + public void testOnCapabilitiesChanged() throws Exception { + final List actualCapabilities = new ArrayList<>(); + monitoringService.registerListener(new NetconfMonitoringService.MonitoringListener() { + @Override + public void onStateChanged(NetconfState state) { + List capability = state.getCapabilities().getCapability(); + for (Uri uri : capability) { + actualCapabilities.add(uri.getValue()); + } + } + }); + HashSet testCaps = new HashSet<>(); + String capUri = "test"; + testCaps.add(new BasicCapability(capUri)); + monitoringService.onCapabilitiesChanged(testCaps, new HashSet()); + Assert.assertTrue(actualCapabilities.contains(capUri)); + actualCapabilities.clear(); + monitoringService.onCapabilitiesChanged(new HashSet(), testCaps); + Assert.assertFalse(actualCapabilities.contains(capUri)); + } + + @Test + public void testonCapabilitiesChanged() throws Exception { + final String toAdd = "toAdd"; + final String toRemove = "toRemove"; + monitoringService.setNotificationPublisher(new BaseNotificationPublisherRegistration() { + @Override + public void onCapabilityChanged(NetconfCapabilityChange capabilityChange) { + Assert.assertEquals(1, capabilityChange.getAddedCapability().size()); + + Assert.assertEquals(toAdd, capabilityChange.getAddedCapability().get(0).getValue()); + Assert.assertEquals(1, capabilityChange.getDeletedCapability().size()); + Assert.assertEquals(toRemove, capabilityChange.getDeletedCapability().get(0).getValue()); + } + + @Override + public void close() { + + } + }); + Set removed = new HashSet<>(); + removed.add(new BasicCapability(toRemove)); + Set added = new HashSet<>(); + added.add(new BasicCapability(toAdd)); + monitoringService.onCapabilitiesChanged(added, removed); + } + + private NetconfMonitoringService.MonitoringListener getMonitoringListener(final AtomicInteger stateChanged) { + return new NetconfMonitoringService.MonitoringListener() { + @Override + public void onStateChanged(NetconfState state) { + stateChanged.incrementAndGet(); + } + }; + } + +} \ No newline at end of file diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/netconf/impl/osgi/NetconfOperationRouterImplTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/netconf/impl/osgi/NetconfOperationRouterImplTest.java new file mode 100644 index 0000000000..027d175d3d --- /dev/null +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/netconf/impl/osgi/NetconfOperationRouterImplTest.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016 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.netconf.impl.osgi; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.util.xml.DocumentedException; +import org.opendaylight.controller.config.util.xml.XmlUtil; +import org.opendaylight.netconf.mapping.api.HandlingPriority; +import org.opendaylight.netconf.mapping.api.NetconfOperation; +import org.opendaylight.netconf.mapping.api.NetconfOperationChainedExecution; +import org.opendaylight.netconf.mapping.api.NetconfOperationService; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +public class NetconfOperationRouterImplTest { + + private static final String TEST_RPC = "\n"; + private static final String MAX_PRIORITY_REPLY = ""; + private static final String DEFAULT_PRIORITY_REPLY = ""; + + private static Document TEST_RPC_DOC; + + @Mock + private NetconfOperationService operationService; + @Mock + private NetconfOperationService operationService2; + @Mock + private NetconfOperation maxPrioMock; + @Mock + private NetconfOperation defaultPrioMock; + + private NetconfOperationRouterImpl operationRouter; + private NetconfOperationRouterImpl emptyOperationRouter; + + @BeforeClass + public static void suiteSetUp() throws IOException, SAXException { + TEST_RPC_DOC = XmlUtil.readXmlToDocument(TEST_RPC); + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + doReturn(HandlingPriority.HANDLE_WITH_MAX_PRIORITY).when(maxPrioMock).canHandle(any(Document.class)); + doReturn(XmlUtil.readXmlToDocument(MAX_PRIORITY_REPLY)).when(maxPrioMock).handle(any(Document.class), any(NetconfOperationChainedExecution.class)); + + doReturn(HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY).when(defaultPrioMock).canHandle(any(Document.class)); + doReturn(XmlUtil.readXmlToDocument(DEFAULT_PRIORITY_REPLY)).when(defaultPrioMock).handle(any(Document.class), any(NetconfOperationChainedExecution.class)); + + Set operations = new HashSet<>(); + operations.add(maxPrioMock); + operations.add(defaultPrioMock); + doReturn(operations).when(operationService).getNetconfOperations(); + doNothing().when(operationService).close(); + + operationRouter = new NetconfOperationRouterImpl(operationService, null, "session-1"); + doReturn(Collections.EMPTY_SET).when(operationService2).getNetconfOperations(); + emptyOperationRouter = new NetconfOperationRouterImpl(operationService2, null, "session-1"); + } + + @Test + public void testOnNetconfMessage() throws Exception { + ArgumentCaptor highPriorityChainEx = ArgumentCaptor.forClass(NetconfOperationChainedExecution.class); + ArgumentCaptor defaultPriorityChainEx = ArgumentCaptor.forClass(NetconfOperationChainedExecution.class); + + final Document document = operationRouter.onNetconfMessage(TEST_RPC_DOC, null); + + //max priority message is first in chain + verify(maxPrioMock).handle(any(Document.class), highPriorityChainEx.capture()); + final NetconfOperationChainedExecution chainedExecution = highPriorityChainEx.getValue(); + Assert.assertFalse(chainedExecution.isExecutionTermination()); + + //execute next in chain + final Document execute = chainedExecution.execute(XmlUtil.newDocument()); + Assert.assertEquals(DEFAULT_PRIORITY_REPLY, XmlUtil.toString(execute).trim()); + + //default priority message is second and last + verify(defaultPrioMock).handle(any(Document.class), defaultPriorityChainEx.capture()); + Assert.assertTrue(defaultPriorityChainEx.getValue().isExecutionTermination()); + + Assert.assertEquals(MAX_PRIORITY_REPLY, XmlUtil.toString(document).trim()); + } + + @Test + public void testOnNetconfMessageFail() throws Exception { + try{ + emptyOperationRouter.onNetconfMessage(TEST_RPC_DOC, null); + Assert.fail("Exception expected"); + } catch (DocumentedException e) { + Assert.assertEquals(e.getErrorTag(), DocumentedException.ErrorTag.operation_not_supported); + } + } + + @Test + public void testClose() throws Exception { + operationRouter.close(); + verify(operationService).close(); + } + +} \ No newline at end of file diff --git a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDevice.java b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDevice.java index fd3399fb9e..bb63554d54 100644 --- a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDevice.java +++ b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDevice.java @@ -43,10 +43,8 @@ import org.opendaylight.netconf.sal.connect.netconf.schema.NetconfRemoteSchemaYa import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer; import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil; import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.$YangModuleInfoImpl; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability; -import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException; @@ -68,26 +66,6 @@ public class NetconfDevice implements RemoteDevice QNAME_TO_SOURCE_ID_FUNCTION = new Function() { @Override public SourceIdentifier apply(final QName input) { @@ -117,8 +95,12 @@ public class NetconfDevice implements RemoteDevice sourceResolverFuture = processingExecutor.submit(task); @@ -215,7 +197,11 @@ public class NetconfDevice implements RemoteDevice filter = NetconfMessageTransformUtil.toFilterStructure(STATE_SCHEMAS_IDENTIFIER, NetconfDevice.INIT_SCHEMA_CTX); + final DataContainerChild filter = NetconfMessageTransformUtil.toFilterStructure(STATE_SCHEMAS_IDENTIFIER, + NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS.getSchemaContext()); GET_SCHEMAS_RPC = Builders.containerBuilder().withNodeIdentifier(toId(NETCONF_GET_QNAME)).withChild(filter).build(); } diff --git a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java index 2ac01caffc..270cdbfb18 100644 --- a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java +++ b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java @@ -8,9 +8,11 @@ package org.opendaylight.netconf.sal.connect.netconf.schema.mapping; import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.EVENT_TIME; +import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.IETF_NETCONF_NOTIFICATIONS; import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_RPC_QNAME; import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_URI; import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath; + import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; @@ -44,7 +46,9 @@ import org.opendaylight.netconf.sal.connect.api.MessageTransformer; import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil; import org.opendaylight.netconf.sal.connect.util.MessageCounter; import org.opendaylight.netconf.util.OrderedNormalizedNodeWriter; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.$YangModuleInfoImpl; import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; +import org.opendaylight.yangtools.yang.binding.YangModuleInfo; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; @@ -68,6 +72,46 @@ import org.w3c.dom.Element; public class NetconfMessageTransformer implements MessageTransformer { + public enum BaseSchema { + + BASE_NETCONF_CTX( + Lists.newArrayList( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.$YangModuleInfoImpl.getInstance() + ) + ), + BASE_NETCONF_CTX_WITH_NOTIFICATIONS( + Lists.newArrayList( + $YangModuleInfoImpl.getInstance(), + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.$YangModuleInfoImpl.getInstance(), + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.$YangModuleInfoImpl.getInstance(), + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.$YangModuleInfoImpl.getInstance() + ) + ); + + private final Map mappedRpcs; + private final SchemaContext schemaContext; + + BaseSchema(List modules) { + try { + final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create(); + moduleInfoBackedContext.addModuleInfos(modules); + schemaContext = moduleInfoBackedContext.tryToCreateSchemaContext().get(); + mappedRpcs = Maps.uniqueIndex(schemaContext.getOperations(), QNAME_FUNCTION); + } catch (final RuntimeException e) { + LOG.error("Unable to prepare schema context for base netconf ops", e); + throw new ExceptionInInitializerError(e); + } + } + + private Map getMappedRpcs() { + return mappedRpcs; + } + + public SchemaContext getSchemaContext() { + return schemaContext; + } + } + public static final String MESSAGE_ID_PREFIX = "m"; private static final Logger LOG= LoggerFactory.getLogger(NetconfMessageTransformer.class); @@ -86,34 +130,25 @@ public class NetconfMessageTransformer implements MessageTransformer MAPPED_BASE_RPCS = Maps.uniqueIndex(BASE_NETCONF_CTX.getOperations(), QNAME_FUNCTION); private final SchemaContext schemaContext; + private final BaseSchema baseSchema; private final MessageCounter counter; private final Map mappedRpcs; private final Multimap mappedNotifications; private final DomToNormalizedNodeParserFactory parserFactory; public NetconfMessageTransformer(final SchemaContext schemaContext, final boolean strictParsing) { + this(schemaContext, strictParsing, BaseSchema.BASE_NETCONF_CTX); + } + + public NetconfMessageTransformer(final SchemaContext schemaContext, final boolean strictParsing, final BaseSchema baseSchema) { this.counter = new MessageCounter(); this.schemaContext = schemaContext; parserFactory = DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, schemaContext, strictParsing); - mappedRpcs = Maps.uniqueIndex(schemaContext.getOperations(), QNAME_FUNCTION); mappedNotifications = Multimaps.index(schemaContext.getNotifications(), QNAME_NOREV_FUNCTION); + this.baseSchema = baseSchema; } @Override @@ -213,9 +248,9 @@ public class NetconfMessageTransformer implements MessageTransformer containerNodeParser = DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, NetconfDevice.INIT_SCHEMA_CTX, false).getContainerNodeParser(); + final ToNormalizedNodeParser containerNodeParser = DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, schemaContext, false).getContainerNodeParser(); final ContainerNode compositeNodeSchemas = containerNodeParser.parse(Collections.singleton(schemasXml.getDocumentElement()), (ContainerSchemaNode) schemasNode); final NetconfStateSchemas schemas = NetconfStateSchemas.create(new RemoteDeviceId("device", new InetSocketAddress(99)), compositeNodeSchemas); diff --git a/opendaylight/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTxTest.java b/opendaylight/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTxTest.java index c708574ce1..82fe4b23e7 100644 --- a/opendaylight/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTxTest.java +++ b/opendaylight/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTxTest.java @@ -33,7 +33,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult; -import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice; +import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer; import org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps; import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil; import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId; @@ -128,7 +128,7 @@ public class NetconfDeviceWriteOnlyTxTest { .doReturn(Futures.immediateFailedCheckedFuture(new IllegalStateException("Failed tx"))) .when(rpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class)); - final WriteRunningTx tx = new WriteRunningTx(id, new NetconfBaseOps(rpc, NetconfDevice.INIT_SCHEMA_CTX), + final WriteRunningTx tx = new WriteRunningTx(id, new NetconfBaseOps(rpc, NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS.getSchemaContext()), false, 60000L); try { tx.delete(LogicalDatastoreType.CONFIGURATION, yangIId); diff --git a/opendaylight/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java b/opendaylight/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java index f8bf554c1c..91279cc1df 100644 --- a/opendaylight/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java +++ b/opendaylight/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformerTest.java @@ -13,6 +13,8 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_CONTENT; +import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_QNAME; import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.GET_SCHEMA_QNAME; import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME; import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME; @@ -46,7 +48,6 @@ import org.junit.Test; import org.opendaylight.controller.config.util.xml.XmlUtil; import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult; import org.opendaylight.netconf.api.NetconfMessage; -import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice; import org.opendaylight.netconf.sal.connect.netconf.schema.NetconfRemoteSchemaYangSourceProvider; import org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps; import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil; @@ -97,6 +98,23 @@ public class NetconfMessageTransformerTest { assertThat(XmlUtil.toString(netconfMessage.getDocument()), CoreMatchers.containsString(" editConfigStructure = createEditConfigStructure(NetconfDevice.INIT_SCHEMA_CTX, id, Optional.absent(), Optional.>fromNullable(schemaNode)); + final DataContainerChild editConfigStructure = createEditConfigStructure(NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS.getSchemaContext(), id, Optional.absent(), Optional.>fromNullable(schemaNode)); final DataContainerChild target = NetconfBaseOps.getTargetNode(NETCONF_CANDIDATE_QNAME);