<packaging>jar</packaging>
<properties>
- <aaa.version>0.4.0-SNAPSHOT</aaa.version>
<commons.opendaylight.version>1.7.0-SNAPSHOT</commons.opendaylight.version>
<controller.mdsal.version>1.4.0-SNAPSHOT</controller.mdsal.version>
<config.version>0.5.0-SNAPSHOT</config.version>
<classifier>features</classifier>
<type>xml</type>
</dependency>
- <dependency>
- <groupId>org.opendaylight.aaa</groupId>
- <artifactId>features-aaa</artifactId>
- <version>${aaa.version}</version>
- <classifier>features</classifier>
- <type>xml</type>
- </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>sal-netconf-connector</artifactId>
<classifier>features</classifier>
<type>xml</type>
</dependency>
- <dependency>
- <groupId>org.opendaylight.aaa</groupId>
- <artifactId>features-aaa</artifactId>
- <classifier>features</classifier>
- <type>xml</type>
- </dependency>
<dependency>
<groupId>org.opendaylight.aaa</groupId>
<artifactId>features-aaa-shiro</artifactId>
<repository>mvn:org.opendaylight.controller/features-config/{{VERSION}}/xml/features</repository>
<repository>mvn:org.opendaylight.controller/features-config-persister/{{VERSION}}/xml/features</repository>
<repository>mvn:org.opendaylight.controller/features-config-netty/{{VERSION}}/xml/features</repository>
- <repository>mvn:org.opendaylight.aaa/features-aaa/${aaa.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.aaa/features-aaa-shiro/${aaa.version}/xml/features</repository>
<feature name='odl-netconf-all' version='${project.version}' description="OpenDaylight :: Netconf :: All">
<feature version='${project.version}'>odl-netconf-api</feature>
version='${project.version}'>
<feature version='${config.version}'>odl-config-api</feature>
<bundle>mvn:org.opendaylight.netconf/netconf-auth/{{VERSION}}</bundle>
- <feature version='${aaa.version}'>odl-aaa-authn</feature>
+ <feature version='${aaa.version}'>odl-aaa-shiro</feature>
<bundle>mvn:org.opendaylight.netconf/aaa-authn-odl-plugin/{{VERSION}}</bundle>
</feature>
version='${project.version}'>
<feature version='${config.version}'>odl-config-api</feature>
<bundle>mvn:org.opendaylight.netconf/netconf-auth/{{VERSION}}</bundle>
- <feature version='${aaa.version}'>odl-aaa-authn-no-cluster</feature>
+ <feature version='${aaa.version}'>odl-aaa-shiro</feature>
<bundle>mvn:org.opendaylight.netconf/aaa-authn-odl-plugin/{{VERSION}}</bundle>
</feature>
</features>
@Override
public void close() {
-
+ for (NetconfOperation netconfOperation : netconfOperations) {
+ if (netconfOperation instanceof AutoCloseable) {
+ try {
+ ((AutoCloseable) netconfOperation).close();
+ } catch (Exception e) {
+ throw new IllegalStateException("Exception while closing " + netconfOperation, e);
+ }
+ }
+ }
}
}
public static final String SOURCE_KEY = "source";
public static final String RPC_KEY = "rpc";
public static final String NOTIFICATION_ELEMENT_NAME = "notification";
+ public static final String EVENT_TIME = "eventTime";
public static final String MESSAGE_ID = "message-id";
public static final String SESSION_ID = "session-id";
public static final String URN_IETF_PARAMS_NETCONF_BASE_1_0 = "urn:ietf:params:netconf:base:1.0";
public static final String URN_IETF_PARAMS_NETCONF_BASE_1_1 = "urn:ietf:params:netconf:base:1.1";
public static final String URN_IETF_PARAMS_XML_NS_NETCONF_EXI_1_0 = "urn:ietf:params:xml:ns:netconf:exi:1.0";
+ public static final String URN_IETF_PARAMS_NETCONF_CAPABILITY_NOTIFICATION_1_0 = "urn:ietf:params:netconf:capability:notification:1.0";
public static final String URN_IETF_PARAMS_NETCONF_CAPABILITY_EXI_1_0 = "urn:ietf:params:netconf:capability:exi:1.0";
public static final String URN_IETF_PARAMS_XML_NS_YANG_IETF_NETCONF_MONITORING = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring";
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
-import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
import org.opendaylight.netconf.client.conf.NetconfClientConfiguration.NetconfClientProtocol;
import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
+import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
import org.opendaylight.protocol.framework.NeverReconnectStrategy;
private final long sessionId;
public TestingNetconfClient(String clientLabel,
- NetconfClientDispatcher netconfClientDispatcher, final NetconfClientConfiguration config) throws InterruptedException {
+ NetconfClientDispatcher netconfClientDispatcher, final NetconfClientConfiguration config) throws InterruptedException {
this.label = clientLabel;
sessionListener = config.getSessionListener();
Future<NetconfClientSession> clientFuture = netconfClientDispatcher.createClient(config);
- clientSession = get(clientFuture);//TODO: make static
+ clientSession = get(clientFuture);
this.sessionId = clientSession.getSessionId();
}
- private NetconfClientSession get(Future<NetconfClientSession> clientFuture) throws InterruptedException {
+ private static NetconfClientSession get(Future<NetconfClientSession> clientFuture) throws InterruptedException {
try {
return clientFuture.get();
} catch (CancellationException e) {
- throw new RuntimeException("Cancelling " + this, e);
+ throw new RuntimeException("Cancelling " + TestingNetconfClient.class.getSimpleName(), e);
} catch (ExecutionException e) {
- throw new IllegalStateException("Unable to create " + this, e);
+ throw new IllegalStateException("Unable to create " + TestingNetconfClient.class.getSimpleName(), e);
}
}
import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.netconf.impl.osgi.NetconfOperationRouter;
+import org.opendaylight.netconf.util.messages.SubtreeFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
Document rpcReply = operationRouter.onNetconfMessage(incomingDocument, session);
- rpcReply = SubtreeFilter.applySubtreeFilter(incomingDocument, rpcReply);
+ rpcReply = SubtreeFilter.applyRpcSubtreeFilter(incomingDocument, rpcReply);
session.onIncommingRpcSuccess();
private final Set<NetconfManagementSession> sessions = new HashSet<>();
private final NetconfOperationServiceFactory netconfOperationProvider;
private final Map<Uri, Capability> capabilities = new HashMap<>();
+ private final Map<String, Map<String, String>> mappedModulesToRevisionToSchema = Maps.newHashMap();
private final Set<MonitoringListener> listeners = Sets.newHashSet();
private volatile BaseNotificationPublisherRegistration notificationPublisher;
@Override
public synchronized String getSchemaForCapability(final String moduleName, final Optional<String> revision) {
- // FIXME not effective at all
-
- Map<String, Map<String, String>> mappedModulesToRevisionToSchema = Maps.newHashMap();
-
- final Collection<Capability> caps = capabilities.values();
-
- for (Capability cap : caps) {
- if (!cap.getModuleName().isPresent()
- || !cap.getRevision().isPresent()
- || !cap.getCapabilitySchema().isPresent()){
- continue;
- }
-
- final String currentModuleName = cap.getModuleName().get();
- Map<String, String> revisionMap = mappedModulesToRevisionToSchema.get(currentModuleName);
- if (revisionMap == null) {
- revisionMap = Maps.newHashMap();
- mappedModulesToRevisionToSchema.put(currentModuleName, revisionMap);
- }
-
- String currentRevision = cap.getRevision().get();
- revisionMap.put(currentRevision, cap.getCapabilitySchema().get());
- }
-
Map<String, String> revisionMapRequest = mappedModulesToRevisionToSchema.get(moduleName);
Preconditions.checkState(revisionMapRequest != null, "Capability for module %s not present, " + ""
- + "available modules : %s", moduleName, Collections2.transform(caps, CAPABILITY_TO_URI));
+ + "available modules : %s", moduleName, Collections2.transform(capabilities.values(), CAPABILITY_TO_URI));
if (revision.isPresent()) {
String schema = revisionMapRequest.get(revision.get());
}
}
+ private synchronized void updateCapabilityToSchemaMap(final Set<Capability> added, final Set<Capability> removed) {
+ for (final Capability cap : added) {
+ if (!isValidModuleCapability(cap)){
+ continue;
+ }
+
+ final String currentModuleName = cap.getModuleName().get();
+ Map<String, String> revisionMap = mappedModulesToRevisionToSchema.get(currentModuleName);
+ if (revisionMap == null) {
+ revisionMap = Maps.newHashMap();
+ mappedModulesToRevisionToSchema.put(currentModuleName, revisionMap);
+ }
+
+ final String currentRevision = cap.getRevision().get();
+ revisionMap.put(currentRevision, cap.getCapabilitySchema().get());
+ }
+ for (final Capability cap : removed) {
+ if (!isValidModuleCapability(cap)){
+ continue;
+ }
+ final Map<String, String> revisionMap = mappedModulesToRevisionToSchema.get(cap.getModuleName().get());
+ if (revisionMap != null) {
+ revisionMap.remove(cap.getRevision().get());
+ if (revisionMap.isEmpty()) {
+ mappedModulesToRevisionToSchema.remove(cap.getModuleName().get());
+ }
+ }
+ }
+ }
+
+ private boolean isValidModuleCapability(Capability cap) {
+ return cap.getModuleName().isPresent()
+ && cap.getRevision().isPresent()
+ && cap.getCapabilitySchema().isPresent();
+ }
+
@Override
public synchronized Capabilities getCapabilities() {
return new CapabilitiesBuilder().setCapability(Lists.newArrayList(capabilities.keySet())).build();
public void onCapabilitiesChanged(Set<Capability> added, Set<Capability> removed) {
onCapabilitiesAdded(added);
onCapabilitiesRemoved(removed);
+ updateCapabilityToSchemaMap(added, removed);
notifyListeners();
// publish notification to notification collector about changed capabilities
+++ /dev/null
-/*
- * Copyright (c) 2013 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;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-import org.opendaylight.netconf.util.messages.NetconfMessageHeader;
-
-@Deprecated
-public class MessageHeaderTest {
- @Test
- public void testFromBytes() {
- final byte[] raw = new byte[] { (byte) 0x0a, (byte) 0x23, (byte) 0x35, (byte) 0x38, (byte) 0x0a };
- NetconfMessageHeader header = NetconfMessageHeader.fromBytes(raw);
- assertEquals(58, header.getLength());
- }
-
- @Test
- public void testToBytes() {
- NetconfMessageHeader header = new NetconfMessageHeader(123);
- assertArrayEquals(new byte[] { (byte) 0x0a, (byte) 0x23, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x0a },
- header.toBytes());
- }
-}
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import com.google.common.base.Charsets;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
+import java.nio.ByteBuffer;
import java.util.Queue;
import org.junit.Before;
import org.junit.Test;
+import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder;
import org.opendaylight.netconf.nettyutil.handler.FramingMechanismHandlerFactory;
import org.opendaylight.netconf.nettyutil.handler.NetconfChunkAggregator;
import org.opendaylight.netconf.nettyutil.handler.NetconfXMLToMessageDecoder;
import org.opendaylight.netconf.util.messages.FramingMechanism;
import org.opendaylight.netconf.util.messages.NetconfMessageConstants;
-import org.opendaylight.netconf.util.messages.NetconfMessageHeader;
import org.opendaylight.netconf.util.test.XmlFileLoader;
-import org.opendaylight.netconf.api.NetconfMessage;
public class MessageParserTest {
byte[] header = new byte[String.valueOf(exptHeaderLength).length()
+ NetconfMessageConstants.MIN_HEADER_LENGTH - 1];
recievedOutbound.getBytes(0, header);
- NetconfMessageHeader messageHeader = NetconfMessageHeader.fromBytes(header);
- assertEquals(exptHeaderLength, messageHeader.getLength());
+ assertEquals(exptHeaderLength, getHeaderLength(header));
testChunkChannel.writeInbound(recievedOutbound);
}
assertNotNull(receivedMessage);
assertXMLEqual(this.msg.getDocument(), receivedMessage.getDocument());
}
+
+ private static long getHeaderLength(byte[] bytes) {
+ byte[] HEADER_START = new byte[] { (byte) 0x0a, (byte) 0x23 };
+ return Long.parseLong(Charsets.US_ASCII.decode(
+ ByteBuffer.wrap(bytes, HEADER_START.length, bytes.length - HEADER_START.length - 1)).toString());
+ }
}
import com.google.common.base.Optional;
import java.net.URI;
import java.util.ArrayList;
-import java.util.Calendar;
+import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
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.common.SimpleDateFormatUtil;
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_CONTENT2 = "content2";
private static final String TEST_MODULE_REV = "1970-01-01";
+ private static final String TEST_MODULE_REV2 = "1970-01-02";
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;
+ private static Date TEST_MODULE_DATE;
+ private static Date TEST_MODULE_DATE2;
- static {
- Calendar calendar = Calendar.getInstance();
- calendar.set(1970, Calendar.JANUARY, 1);
- TEST_MODULE_DATE = calendar.getTime();
- }
+ private YangModuleCapability moduleCapability1;
+ private YangModuleCapability moduleCapability2;
private final Set<Capability> CAPABILITIES = new HashSet<>();
private NetconfMonitoringServiceImpl monitoringService;
-
@Mock
private Module moduleMock;
@Mock
+ private Module moduleMock2;
+ @Mock
private NetconfOperationServiceFactory operationServiceFactoryMock;
@Mock
private NetconfManagementSession sessionMock;
+ @BeforeClass
+ public static void suiteSetUp() throws Exception {
+ TEST_MODULE_DATE = SimpleDateFormatUtil.getRevisionFormat().parse(TEST_MODULE_REV);
+ TEST_MODULE_DATE2= SimpleDateFormatUtil.getRevisionFormat().parse(TEST_MODULE_REV2);
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
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();
+ moduleCapability1 = new YangModuleCapability(moduleMock, TEST_MODULE_CONTENT);
+
+ CAPABILITIES.add(moduleCapability1);
+
+ doReturn(new URI(TEST_MODULE_NAMESPACE.getValue())).when(moduleMock2).getNamespace();
+ doReturn(TEST_MODULE_NAME).when(moduleMock2).getName();
+ doReturn(TEST_MODULE_DATE2).when(moduleMock2).getRevision();
+ moduleCapability2 = new YangModuleCapability(moduleMock2, TEST_MODULE_CONTENT2);
- 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<Capability>());
+ monitoringService.onCapabilitiesChanged(CAPABILITIES, Collections.emptySet());
doReturn(new SessionBuilder().build()).when(sessionMock).toManagementSession();
}
@Test
public void testGetSchemaForCapability() throws Exception {
- String schema = monitoringService.getSchemaForCapability(TEST_MODULE_NAME, Optional.of(TEST_MODULE_REV));
+ //test multiple revisions of the same capability
+ monitoringService.onCapabilitiesChanged(Collections.singleton(moduleCapability2), Collections.emptySet());
+ final String schema = monitoringService.getSchemaForCapability(TEST_MODULE_NAME, Optional.of(TEST_MODULE_REV));
Assert.assertEquals(TEST_MODULE_CONTENT, schema);
-
+ final String schema2 = monitoringService.getSchemaForCapability(TEST_MODULE_NAME, Optional.of(TEST_MODULE_REV2));
+ Assert.assertEquals(TEST_MODULE_CONTENT2, schema2);
+ //remove one revision
+ monitoringService.onCapabilitiesChanged(Collections.emptySet(), Collections.singleton(moduleCapability1));
+ //only one revision present
+ final String schema3 = monitoringService.getSchemaForCapability(TEST_MODULE_NAME, Optional.absent());
+ Assert.assertEquals(TEST_MODULE_CONTENT2, schema3);
}
@Test
*/
public static final Date UNKNOWN_EVENT_TIME = new Date(0);
+ private final Date eventTime;
+
/**
* Create new notification and capture the timestamp in the constructor
*/
*/
public NetconfNotification(final Document notificationContent, final Date eventTime) {
super(wrapNotification(notificationContent, eventTime));
+ this.eventTime = eventTime;
+ }
+
+ /**
+ * @return notification event time
+ */
+ public Date getEventTime() {
+ return eventTime;
}
private static Document wrapNotification(final Document notificationContent, final Date eventTime) {
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
+import java.util.Date;
import java.util.List;
import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.netconf.notifications.NotificationListenerRegistration;
import org.opendaylight.netconf.notifications.impl.NetconfNotificationManager;
import org.opendaylight.netconf.util.mapping.AbstractSingletonNetconfOperation;
+import org.opendaylight.netconf.util.messages.SubtreeFilter;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInput;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
import org.slf4j.Logger;
// Binding doesn't support anyxml nodes yet, so filter could not be retrieved
// xml -> normalized node -> CreateSubscriptionInput conversion could be slower than current approach
- // FIXME filter could be supported same way as netconf server filters get and get-config results
final Optional<XmlElement> filter = operationElement.getOnlyChildElementWithSameNamespaceOptionally("filter");
- Preconditions.checkArgument(filter.isPresent() == false, "Filter element not yet supported");
// Replay not supported
final Optional<XmlElement> startTime = operationElement.getOnlyChildElementWithSameNamespaceOptionally("startTime");
}
final NotificationListenerRegistration notificationListenerRegistration =
- notifications.registerNotificationListener(streamNameType, new NotificationSubscription(netconfSession));
+ notifications.registerNotificationListener(streamNameType, new NotificationSubscription(netconfSession, filter));
subscriptions.add(notificationListenerRegistration);
return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
private static class NotificationSubscription implements NetconfNotificationListener {
private final NetconfSession currentSession;
+ private final Optional<XmlElement> filter;
- public NotificationSubscription(final NetconfSession currentSession) {
+ public NotificationSubscription(final NetconfSession currentSession, final Optional<XmlElement> filter) {
this.currentSession = currentSession;
+ this.filter = filter;
}
@Override
public void onNotification(final StreamNameType stream, final NetconfNotification notification) {
- currentSession.sendMessage(notification);
+ if (filter.isPresent()) {
+ try {
+ final Optional<Document> filtered = SubtreeFilter.applySubtreeNotificationFilter(this.filter.get(), notification.getDocument());
+ if (filtered.isPresent()) {
+ final Date eventTime = notification.getEventTime();
+ currentSession.sendMessage(new NetconfNotification(filtered.get(), eventTime));
+ }
+ } catch (DocumentedException e) {
+ LOG.warn(e.toString());
+ currentSession.sendMessage(notification);
+ }
+ } else {
+ currentSession.sendMessage(notification);
+ }
}
}
}
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-parser-impl</artifactId>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-jmx-generator-plugin</artifactId>
- </dependency>
<dependency>
<groupId>org.opendaylight.netconf</groupId>
<artifactId>sal-netconf-connector</artifactId>
RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);
RemoteDeviceHandler<NetconfSessionPreferences> salFacade =
- createSalFacade(remoteDeviceId, domBroker, bindingAwareBroker, defaultRequestTimeoutMillis);
+ createSalFacade(remoteDeviceId, domBroker, bindingAwareBroker);
if (keepaliveDelay > 0) {
LOG.warn("Adding keepalive facade, for device {}", nodeId);
- salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade, keepaliveExecutor.getExecutor(), keepaliveDelay);
+ salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade, keepaliveExecutor.getExecutor(), keepaliveDelay, defaultRequestTimeoutMillis);
}
final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = setupSchemaCacheDTO(nodeId, node);
.build();
}
- protected abstract RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id, final Broker domBroker, final BindingAwareBroker bindingBroker, long defaultRequestTimeoutMillis);
+ protected abstract RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id, final Broker domBroker, final BindingAwareBroker bindingBroker);
@Override
public abstract ConnectionStatusListenerRegistration registerConnectionStatusListener(NodeId node, RemoteDeviceHandler<NetconfSessionPreferences> listener);
RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);
RemoteDeviceHandler<NetconfSessionPreferences> salFacade =
- createSalFacade(remoteDeviceId, domBroker, bindingAwareBroker, defaultRequestTimeoutMillis);
+ createSalFacade(remoteDeviceId, domBroker, bindingAwareBroker);
if (keepaliveDelay > 0) {
LOG.warn("Adding keepalive facade, for device {}", nodeId);
- salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade, keepaliveExecutor.getExecutor(), keepaliveDelay);
+ salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade, keepaliveExecutor.getExecutor(), keepaliveDelay, defaultRequestTimeoutMillis);
}
final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = setupSchemaCacheDTO(nodeId, node);
}
@Override
- protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id, final Broker domBroker, final BindingAwareBroker bindingBroker, long defaultRequestTimeoutMillis) {
- return new TopologyMountPointFacade(topologyId, id, domBroker, bindingBroker, defaultRequestTimeoutMillis);
+ protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id, final Broker domBroker, final BindingAwareBroker bindingBroker) {
+ return new TopologyMountPointFacade(topologyId, id, domBroker, bindingBroker);
}
@Override
}
@Override
- protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(RemoteDeviceId id, Broker domBroker, BindingAwareBroker bindingBroker, long defaultRequestTimeoutMillis) {
- return new NetconfDeviceSalFacade(id, domBroker, bindingAwareBroker, defaultRequestTimeoutMillis);
+ protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(RemoteDeviceId id, Broker domBroker, BindingAwareBroker bindingBroker) {
+ return new NetconfDeviceSalFacade(id, domBroker, bindingAwareBroker);
}
@Override
public NetconfDeviceMasterDataBroker(final ActorSystem actorSystem, final RemoteDeviceId id,
final SchemaContext schemaContext, final DOMRpcService rpc,
- final NetconfSessionPreferences netconfSessionPreferences, final long requestTimeoutMillis) {
+ final NetconfSessionPreferences netconfSessionPreferences) {
this.id = id;
- delegateBroker = new NetconfDeviceDataBroker(id, schemaContext, rpc, netconfSessionPreferences, requestTimeoutMillis);
+ delegateBroker = new NetconfDeviceDataBroker(id, schemaContext, rpc, netconfSessionPreferences);
this.actorSystem = actorSystem;
// only ever need 1 readTx since it doesnt need to be closed
private final RemoteDeviceId id;
private final Broker domBroker;
private final BindingAwareBroker bindingBroker;
- private final long defaultRequestTimeoutMillis;
private SchemaContext remoteSchemaContext = null;
private NetconfSessionPreferences netconfSessionPreferences = null;
public TopologyMountPointFacade(final String topologyId,
final RemoteDeviceId id,
final Broker domBroker,
- final BindingAwareBroker bindingBroker,
- long defaultRequestTimeoutMillis) {
+ final BindingAwareBroker bindingBroker) {
this.topologyId = topologyId;
this.id = id;
this.domBroker = domBroker;
this.bindingBroker = bindingBroker;
- this.defaultRequestTimeoutMillis = defaultRequestTimeoutMillis;
this.salProvider = new ClusteredNetconfDeviceMountInstanceProxy(id);
registerToSal(domBroker);
}
deviceDataBroker = TypedActor.get(context).typedActorOf(new TypedProps<>(ProxyNetconfDeviceDataBroker.class, new Creator<NetconfDeviceMasterDataBroker>() {
@Override
public NetconfDeviceMasterDataBroker create() throws Exception {
- return new NetconfDeviceMasterDataBroker(actorSystem, id, remoteSchemaContext, deviceRpc, netconfSessionPreferences, defaultRequestTimeoutMillis);
+ return new NetconfDeviceMasterDataBroker(actorSystem, id, remoteSchemaContext, deviceRpc, netconfSessionPreferences);
}
}), MOUNT_POINT);
LOG.debug("Master data broker registered on path {}", TypedActor.get(actorSystem).getActorRefFor(deviceDataBroker).path());
}
@Override
- protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(RemoteDeviceId id, Broker domBroker, BindingAwareBroker bindingBroker, long defaultRequestTimeoutMillis) {
+ protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(RemoteDeviceId id, Broker domBroker, BindingAwareBroker bindingBroker) {
return salFacade;
}
MockitoAnnotations.initMocks(this);
- mountPointFacade = new TopologyMountPointFacade(TOPOLOGY_ID, REMOTE_DEVICE_ID, domBroker, bindingBroker, 1L);
+ mountPointFacade = new TopologyMountPointFacade(TOPOLOGY_ID, REMOTE_DEVICE_ID, domBroker, bindingBroker);
mountPointFacade.registerConnectionStatusListener(connectionStatusListener1);
mountPointFacade.registerConnectionStatusListener(connectionStatusListener2);
+++ /dev/null
-/*
- * Copyright (c) 2013 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.util.messages;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Preconditions;
-import java.nio.ByteBuffer;
-
-/**
- * Netconf message header is used only when chunked framing mechanism is
- * supported. The header consists of only the length field.
- */
-@Deprecated
-public final class NetconfMessageHeader {
- // \n#<length>\n
- private static final byte[] HEADER_START = new byte[] { (byte) 0x0a, (byte) 0x23 };
- private static final byte HEADER_END = (byte) 0x0a;
- private final long length;
-
- public NetconfMessageHeader(final long length) {
- Preconditions.checkArgument(length < Integer.MAX_VALUE && length > 0);
- this.length = length;
- }
-
- public byte[] toBytes() {
- return toBytes(this.length);
- }
-
- // FIXME: improve precision to long
- public int getLength() {
- return (int) this.length;
- }
-
- public static NetconfMessageHeader fromBytes(final byte[] bytes) {
- // the length is variable therefore bytes between headerBegin and
- // headerEnd mark the length
- // the length should be only numbers and therefore easily parsed with
- // ASCII
- long length = Long.parseLong(Charsets.US_ASCII.decode(
- ByteBuffer.wrap(bytes, HEADER_START.length, bytes.length - HEADER_START.length - 1)).toString());
-
- return new NetconfMessageHeader(length);
- }
-
- public static byte[] toBytes(final long length) {
- final byte[] l = String.valueOf(length).getBytes(Charsets.US_ASCII);
- final byte[] h = new byte[HEADER_START.length + l.length + 1];
- System.arraycopy(HEADER_START, 0, h, 0, HEADER_START.length);
- System.arraycopy(l, 0, h, HEADER_START.length, l.length);
- System.arraycopy(new byte[] { HEADER_END }, 0, h, HEADER_START.length + l.length, 1);
- return h;
- }
-}
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.netconf.impl;
+package org.opendaylight.netconf.util.messages;
import com.google.common.base.Optional;
import java.io.IOException;
import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.config.util.xml.XmlUtil;
-import org.opendaylight.netconf.util.mapping.AbstractNetconfOperation.OperationNameAndNamespace;
import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.netconf.util.mapping.AbstractNetconfOperation.OperationNameAndNamespace;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Attr;
public class SubtreeFilter {
private static final Logger LOG = LoggerFactory.getLogger(SubtreeFilter.class);
- static Document applySubtreeFilter(Document requestDocument, Document rpcReply) throws DocumentedException {
+ public static Document applyRpcSubtreeFilter(Document requestDocument, Document rpcReply) throws DocumentedException {
OperationNameAndNamespace operationNameAndNamespace = new OperationNameAndNamespace(requestDocument);
if (XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0.equals(operationNameAndNamespace.getNamespace()) &&
XmlNetconfConstants.GET.equals(operationNameAndNamespace.getOperationName()) ||
return rpcReply;
}
- // FIXME: rpcReply document must be reread otherwise some nodes do not inherit namespaces. (services/service)
- try {
- rpcReply = XmlUtil.readXmlToDocument(XmlUtil.toString(rpcReply, true));
- } catch (SAXException | IOException e) {
- LOG.error("Cannot transform document", e);
- throw new DocumentedException("Cannot transform document" + e);
- }
+ rpcReply = reReadDocument(rpcReply);
XmlElement filter = maybeFilter.get();
- if ("subtree".equals(filter.getAttribute("type"))||
- "subtree".equals(filter.getAttribute("type", XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0))) {
+ if (isSupported(filter)) {
// do
return filtered(maybeFilter.get(), rpcReply);
return rpcReply; // return identical document
}
+ /**
+ * Filters notification content. If filter type isn't of type "subtree", returns unchanged notification content.
+ * If no match is found, absent is returned.
+ * @param filter filter
+ * @param notification notification
+ * @return document containing filtered notification content
+ * @throws DocumentedException
+ */
+ public static Optional<Document> applySubtreeNotificationFilter(XmlElement filter, Document notification) throws DocumentedException {
+ notification = reReadDocument(notification);
+ removeEventTimeNode(notification);
+ if (isSupported(filter)) {
+ return Optional.fromNullable(filteredNotification(filter, notification));
+ }
+ return Optional.of(extractNotificationContent(notification));
+ }
+
+ private static Document reReadDocument(Document notification) throws DocumentedException {
+ // FIXME: rpcReply document must be reread otherwise some nodes do not inherit namespaces. (services/service)
+ try {
+ notification = XmlUtil.readXmlToDocument(XmlUtil.toString(notification, true));
+ } catch (SAXException | IOException e) {
+ LOG.error("Cannot transform document", e);
+ throw new DocumentedException("Cannot transform document" + e);
+ }
+ return notification;
+ }
+
+ private static void removeEventTimeNode(Document document) {
+ final Node eventTimeNode = document.getDocumentElement().getElementsByTagNameNS(
+ XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_CAPABILITY_NOTIFICATION_1_0, XmlNetconfConstants.EVENT_TIME).item(0);
+ document.getDocumentElement().removeChild(eventTimeNode);
+ }
+
+ private static boolean isSupported(XmlElement filter) {
+ return "subtree".equals(filter.getAttribute("type"))||
+ "subtree".equals(filter.getAttribute("type", XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0));
+ }
+
+ private static Document extractNotificationContent(Document notification) throws DocumentedException {
+ XmlElement root = XmlElement.fromDomElement(notification.getDocumentElement());
+ XmlElement content = root.getOnlyChildElement();
+ notification.removeChild(root.getDomElement());
+ notification.appendChild(content.getDomElement());
+ return notification;
+ }
+
+ private static Document filteredNotification(XmlElement filter, Document originalNotification) throws DocumentedException {
+ Document result = XmlUtil.newDocument();
+ XmlElement dataSrc = XmlElement.fromDomDocument(originalNotification);
+ Element dataDst = (Element) result.importNode(dataSrc.getDomElement(), false);
+ for (XmlElement filterChild : filter.getChildElements()) {
+ addSubtree2(filterChild, dataSrc.getOnlyChildElement(), XmlElement.fromDomElement(dataDst));
+ }
+ if(dataDst.getFirstChild() != null) {
+ result.appendChild(dataDst.getFirstChild());
+ return result;
+ } else {
+ return null;
+ }
+ }
+
private static Document filtered(XmlElement filter, Document originalReplyDocument) throws DocumentedException {
Document result = XmlUtil.newDocument();
// even if filter is empty, copy /rpc/data
+++ /dev/null
-/*
- * Copyright (c) 2014 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.util.messages;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import com.google.common.base.Charsets;
-import org.junit.Test;
-
-@Deprecated
-public class NetconfMessageHeaderTest {
- @Test
- public void testGet() throws Exception {
- NetconfMessageHeader header = new NetconfMessageHeader(10);
- assertEquals(header.getLength(), 10);
-
- byte[] expectedValue = "\n#10\n".getBytes(Charsets.US_ASCII);
- assertArrayEquals(expectedValue, header.toBytes());
- }
-}
--- /dev/null
+/*
+ * 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.util.messages;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Optional;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+@RunWith(value = Parameterized.class)
+public class SubtreeFilterNotificationTest {
+ private static final Logger LOG = LoggerFactory.getLogger(SubtreeFilterRpcTest.class);
+
+ private final int directoryIndex;
+
+ @Parameters
+ public static Collection<Object[]> data() {
+ List<Object[]> result = new ArrayList<>();
+ for (int i = 0; i < 5; i++) {
+ result.add(new Object[]{i});
+ }
+ return result;
+ }
+
+ public SubtreeFilterNotificationTest(int directoryIndex) {
+ this.directoryIndex = directoryIndex;
+ }
+
+ @Before
+ public void setUp(){
+ XMLUnit.setIgnoreWhitespace(true);
+ }
+
+ @Test
+ public void testFilterNotification() throws Exception {
+ XmlElement filter = XmlElement.fromDomDocument(getDocument("filter.xml"));
+ Document preFilterDocument = getDocument("pre-filter.xml");
+ Document postFilterDocument = getDocument("post-filter.xml");
+ Optional<Document> actualPostFilterDocumentOpt = SubtreeFilter.applySubtreeNotificationFilter(filter, preFilterDocument);
+ if(actualPostFilterDocumentOpt.isPresent()) {
+ Document actualPostFilterDocument = actualPostFilterDocumentOpt.get();
+ LOG.info("Actual document: {}", XmlUtil.toString(actualPostFilterDocument));
+ Diff diff = XMLUnit.compareXML(postFilterDocument, actualPostFilterDocument);
+ assertTrue(diff.toString(), diff.similar());
+ } else {
+ assertEquals("empty", XmlElement.fromDomDocument(postFilterDocument).getName());
+ }
+ }
+
+ public Document getDocument(String fileName) throws SAXException, IOException {
+ return XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/subtree/notification/" + directoryIndex + "/" +
+ fileName));
+ }
+}
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.netconf.impl;
+package org.opendaylight.netconf.util.messages;
import static org.junit.Assert.assertTrue;
import org.xml.sax.SAXException;
@RunWith(value = Parameterized.class)
-public class SubtreeFilterTest {
- private static final Logger LOG = LoggerFactory.getLogger(SubtreeFilterTest.class);
+public class SubtreeFilterRpcTest {
+ private static final Logger LOG = LoggerFactory.getLogger(SubtreeFilterRpcTest.class);
private final int directoryIndex;
return result;
}
- public SubtreeFilterTest(int directoryIndex) {
+ public SubtreeFilterRpcTest(int directoryIndex) {
this.directoryIndex = directoryIndex;
}
Document requestDocument = getDocument("request.xml");
Document preFilterDocument = getDocument("pre-filter.xml");
Document postFilterDocument = getDocument("post-filter.xml");
- Document actualPostFilterDocument = SubtreeFilter.applySubtreeFilter(requestDocument, preFilterDocument);
+ Document actualPostFilterDocument = SubtreeFilter.applyRpcSubtreeFilter(requestDocument, preFilterDocument);
LOG.info("Actual document: {}", XmlUtil.toString(actualPostFilterDocument));
Diff diff = XMLUnit.compareXML(postFilterDocument, actualPostFilterDocument);
assertTrue(diff.toString(), diff.similar());
}
public Document getDocument(String fileName) throws SAXException, IOException {
- return XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/subtree/" + directoryIndex + "/" +
+ return XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/subtree/rpc/" + directoryIndex + "/" +
fileName));
}
}
--- /dev/null
+<!--
+ ~ 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
+ -->
+<filter xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0" type="subtree">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username/>
+ <session-id/>
+ </netconf-session-end>
+</filter>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ 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
+ -->
+<netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+</netconf-session-end>
+
+
+
--- /dev/null
+<!--
+ ~ 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
+ -->
+<notification xmlns="urn:ietf:params:netconf:capability:notification:1.0">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+ </netconf-session-end>
+ <eventTime>2016-03-17T13:15:12+01:00</eventTime>
+</notification>
--- /dev/null
+<!--
+ ~ 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
+ -->
+<filter xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0" type="unsupported">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username/>
+ <session-id/>
+ </netconf-session-end>
+</filter>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ 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
+ -->
+<netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+</netconf-session-end>
--- /dev/null
+<!--
+ ~ 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
+ -->
+<notification xmlns="urn:ietf:params:netconf:capability:notification:1.0">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+ </netconf-session-end>
+ <eventTime>2016-03-17T13:15:12+01:00</eventTime>
+</notification>
--- /dev/null
+<!--
+ ~ 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
+ -->
+<filter xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0" type="unsupported">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username/>
+ <session-id/>
+ </netconf-session-end>
+</filter>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ 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
+ -->
+<netconf-session-start xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+</netconf-session-start>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ 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
+ -->
+<notification xmlns="urn:ietf:params:netconf:capability:notification:1.0">
+ <netconf-session-start xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+ </netconf-session-start>
+ <eventTime>2016-03-17T13:15:04+01:00</eventTime>
+</notification>
--- /dev/null
+<!--
+ ~ 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
+ -->
+<filter xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0" type="subtree">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username/>
+ <session-id/>
+ </netconf-session-end>
+</filter>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ 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
+ -->
+<empty/>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ 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
+ -->
+<notification xmlns="urn:ietf:params:netconf:capability:notification:1.0">
+ <netconf-session-start xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+ </netconf-session-start>
+ <eventTime>2016-03-17T13:15:04+01:00</eventTime>
+</notification>
--- /dev/null
+<!--
+ ~ 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
+ -->
+<filter xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0" type="subtree">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications"/>
+</filter>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+</netconf-session-end>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ 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
+ -->
+<notification xmlns="urn:ietf:params:netconf:capability:notification:1.0">
+ <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications">
+ <username>admin</username>
+ <session-id>2</session-id>
+ <source-host>127.0.0.1</source-host>
+ </netconf-session-end>
+ <eventTime>2016-03-17T13:15:12+01:00</eventTime>
+</notification>
\ No newline at end of file
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</dependency>
- <dependency>
- <groupId>org.powermock</groupId>
- <artifactId>powermock-api-mockito</artifactId>
- <version>1.6.4</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.powermock</groupId>
- <artifactId>powermock-module-junit4</artifactId>
- <version>1.6.4</version>
- <scope>test</scope>
- </dependency>
</dependencies>
<scm>
final ExecutorService globalProcessingExecutor = processingExecutor.getExecutor();
RemoteDeviceHandler<NetconfSessionPreferences> salFacade
- = new NetconfDeviceSalFacade(id, domRegistry, bindingRegistry, getDefaultRequestTimeoutMillis());
+ = new NetconfDeviceSalFacade(id, domRegistry, bindingRegistry);
final Long keepaliveDelay = getKeepaliveDelay();
if (shouldSendKeepalive()) {
// Keepalive executor is optional for now and a default instance is supported
final ScheduledExecutorService executor = keepaliveExecutor == null ? DEFAULT_KEEPALIVE_EXECUTOR : keepaliveExecutor.getExecutor();
- salFacade = new KeepaliveSalFacade(id, salFacade, executor, keepaliveDelay);
+ salFacade = new KeepaliveSalFacade(id, salFacade, executor, keepaliveDelay, getDefaultRequestTimeoutMillis());
}
// Setup information related to the SchemaRegistry, SchemaResourceFactory, etc.
}
private void setUpSchema(final DeviceSources result) {
- processingExecutor.submit(new RecursiveSchemaSetup(result, remoteSessionCapabilities, listener));
+ processingExecutor.submit(new SchemaSetup(result, remoteSessionCapabilities, listener));
}
@Override
/**
* Schema builder that tries to build schema context from provided sources or biggest subset of it.
*/
- private final class RecursiveSchemaSetup implements Runnable {
+ private final class SchemaSetup implements Runnable {
private final DeviceSources deviceSources;
private final NetconfSessionPreferences remoteSessionCapabilities;
private final RemoteDeviceCommunicator<NetconfMessage> listener;
private final NetconfDeviceCapabilities capabilities;
- public RecursiveSchemaSetup(final DeviceSources deviceSources, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceCommunicator<NetconfMessage> listener) {
+ public SchemaSetup(final DeviceSources deviceSources, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceCommunicator<NetconfMessage> listener) {
this.deviceSources = deviceSources;
this.remoteSessionCapabilities = remoteSessionCapabilities;
this.listener = listener;
}
/**
- * Recursively build schema context, in case of success or final failure notify device
+ * Build schema context, in case of success or final failure notify device
*/
- // FIXME reimplement without recursion
- private void setUpSchema(final Collection<SourceIdentifier> requiredSources) {
- LOG.trace("{}: Trying to build schema context from {}", id, requiredSources);
-
- // If no more sources, fail
- if(requiredSources.isEmpty()) {
- final IllegalStateException cause = new IllegalStateException(id + ": No more sources for schema context");
- handleSalInitializationFailure(cause, listener);
- salFacade.onDeviceFailed(cause);
- return;
- }
-
- final CheckedFuture<SchemaContext, SchemaResolutionException> schemaBuilderFuture = schemaContextFactory.createSchemaContext(requiredSources);
-
- final FutureCallback<SchemaContext> RecursiveSchemaBuilderCallback = new FutureCallback<SchemaContext>() {
-
- @Override
- public void onSuccess(final SchemaContext result) {
+ private void setUpSchema(Collection<SourceIdentifier> requiredSources) {
+ while (!requiredSources.isEmpty()) {
+ LOG.trace("{}: Trying to build schema context from {}", id, requiredSources);
+ try {
+ final CheckedFuture<SchemaContext, SchemaResolutionException> schemaBuilderFuture = schemaContextFactory.createSchemaContext(requiredSources);
+ final SchemaContext result = schemaBuilderFuture.checkedGet();
LOG.debug("{}: Schema context built successfully from {}", id, requiredSources);
final Collection<QName> filteredQNames = Sets.difference(deviceSources.getRequiredSourcesQName(), capabilities.getUnresolvedCapabilites().keySet());
capabilities.addCapabilities(filteredQNames);
capabilities.addNonModuleBasedCapabilities(remoteSessionCapabilities.getNonModuleCaps());
handleSalInitializationSuccess(result, remoteSessionCapabilities, getDeviceSpecificRpc(result));
- }
-
- @Override
- public void onFailure(final Throwable t) {
- // In case source missing, try without it
- if (t instanceof MissingSchemaSourceException) {
+ return;
+ } catch (Throwable t) {
+ if (t instanceof MissingSchemaSourceException){
+ // In case source missing, try without it
final SourceIdentifier missingSource = ((MissingSchemaSourceException) t).getSourceId();
LOG.warn("{}: Unable to build schema context, missing source {}, will reattempt without it", id, missingSource);
LOG.debug("{}: Unable to build schema context, missing source {}, will reattempt without it", t);
if (!qNameOfMissingSource.isEmpty()) {
capabilities.addUnresolvedCapabilities(qNameOfMissingSource, UnavailableCapability.FailureReason.MissingSource);
}
- setUpSchema(stripMissingSource(requiredSources, missingSource));
-
- // In case resolution error, try only with resolved sources
+ requiredSources = stripMissingSource(requiredSources, missingSource);
} else if (t instanceof SchemaResolutionException) {
- // TODO check for infinite loop
- final SchemaResolutionException resolutionException = (SchemaResolutionException) t;
+ // In case resolution error, try only with resolved sources
+ SchemaResolutionException resolutionException = (SchemaResolutionException) t;
final Set<SourceIdentifier> unresolvedSources = resolutionException.getUnsatisfiedImports().keySet();
capabilities.addUnresolvedCapabilities(getQNameFromSourceIdentifiers(unresolvedSources), UnavailableCapability.FailureReason.UnableToResolve);
LOG.warn("{}: Unable to build schema context, unsatisfied imports {}, will reattempt with resolved only", id, resolutionException.getUnsatisfiedImports());
LOG.debug("{}: Unable to build schema context, unsatisfied imports {}, will reattempt with resolved only", resolutionException);
- setUpSchema(resolutionException.getResolvedSources());
- // unknown error, fail
+ requiredSources = resolutionException.getResolvedSources();
} else {
+ // unknown error, fail
handleSalInitializationFailure(t, listener);
+ return;
}
}
- };
-
- Futures.addCallback(schemaBuilderFuture, RecursiveSchemaBuilderCallback);
+ }
+ // No more sources, fail
+ final IllegalStateException cause = new IllegalStateException(id + ": No more sources for schema context");
+ handleSalInitializationFailure(cause, listener);
+ salFacade.onDeviceFailed(cause);
}
+
protected NetconfDeviceRpc getDeviceSpecificRpc(final SchemaContext result) {
return new NetconfDeviceRpc(result, listener, new NetconfMessageTransformer(result, true));
}
// 2 minutes keepalive delay by default
private static final long DEFAULT_DELAY = TimeUnit.MINUTES.toSeconds(2);
+ // 1 minute transaction timeout by default
+ private static final long DEFAULT_TRANSACTION_TIMEOUT_MILLI = TimeUnit.MILLISECONDS.toMillis(60000);
+
private final RemoteDeviceId id;
private final RemoteDeviceHandler<NetconfSessionPreferences> salFacade;
private final ScheduledExecutorService executor;
private final long keepaliveDelaySeconds;
private final ResetKeepalive resetKeepaliveTask;
+ private final long defaultRequestTimeoutMillis;
private volatile NetconfDeviceCommunicator listener;
private volatile ScheduledFuture<?> currentKeepalive;
private volatile DOMRpcService currentDeviceRpc;
public KeepaliveSalFacade(final RemoteDeviceId id, final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
- final ScheduledExecutorService executor, final long keepaliveDelaySeconds) {
+ final ScheduledExecutorService executor, final long keepaliveDelaySeconds, final long defaultRequestTimeoutMillis) {
this.id = id;
this.salFacade = salFacade;
this.executor = executor;
this.keepaliveDelaySeconds = keepaliveDelaySeconds;
+ this.defaultRequestTimeoutMillis = defaultRequestTimeoutMillis;
this.resetKeepaliveTask = new ResetKeepalive();
}
public KeepaliveSalFacade(final RemoteDeviceId id, final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
final ScheduledExecutorService executor) {
- this(id, salFacade, executor, DEFAULT_DELAY);
+ this(id, salFacade, executor, DEFAULT_DELAY, DEFAULT_TRANSACTION_TIMEOUT_MILLI);
}
/**
@Override
public void onDeviceConnected(final SchemaContext remoteSchemaContext, final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc) {
this.currentDeviceRpc = deviceRpc;
- final DOMRpcService deviceRpc1 = new KeepaliveDOMRpcService(deviceRpc, resetKeepaliveTask);
+ final DOMRpcService deviceRpc1 = new KeepaliveDOMRpcService(deviceRpc, resetKeepaliveTask, defaultRequestTimeoutMillis, executor);
salFacade.onDeviceConnected(remoteSchemaContext, netconfSessionPreferences, deviceRpc1);
LOG.debug("{}: Netconf session initiated, starting keepalives", id);
/**
* Reset keepalive after each RPC response received
*/
- private class ResetKeepalive implements com.google.common.util.concurrent.FutureCallback<DOMRpcResult> {
+ private class ResetKeepalive implements FutureCallback<DOMRpcResult> {
@Override
public void onSuccess(@Nullable final DOMRpcResult result) {
// No matter what response we got, rpc-reply or rpc-error, we got it from device so the netconf session is OK
@Override
public void onFailure(@Nonnull final Throwable t) {
- // User/Application RPC failed (The RPC did not reach the remote device.
+ // User/Application RPC failed (The RPC did not reach the remote device or .. TODO what other reasons could cause this ?)
// There is no point in keeping this session. Reconnect.
LOG.warn("{}: Rpc failure detected. Reconnecting netconf session", id, t);
reconnect();
}
}
+ /*
+ * Request timeout task is called once the defaultRequestTimeoutMillis is
+ * reached. At this moment, if the request is not yet finished, we cancel
+ * it.
+ */
+ private static final class RequestTimeoutTask implements Runnable {
+
+ private final CheckedFuture<DOMRpcResult, DOMRpcException> rpcResultFuture;
+
+ public RequestTimeoutTask(final CheckedFuture<DOMRpcResult, DOMRpcException> rpcResultFuture) {
+ this.rpcResultFuture = rpcResultFuture;
+ }
+
+ @Override
+ public void run() {
+ if (!rpcResultFuture.isDone()) {
+ rpcResultFuture.cancel(true);
+ }
+ }
+ }
+
/**
- * DOMRpcService proxy that attaches reset-keepalive-task to each RPC invocation.
+ * DOMRpcService proxy that attaches reset-keepalive-task and schedule
+ * request-timeout-task to each RPC invocation.
*/
private static final class KeepaliveDOMRpcService implements DOMRpcService {
private final DOMRpcService deviceRpc;
private ResetKeepalive resetKeepaliveTask;
+ private final long defaultRequestTimeoutMillis;
+ private final ScheduledExecutorService executor;
- public KeepaliveDOMRpcService(final DOMRpcService deviceRpc, final ResetKeepalive resetKeepaliveTask) {
+ public KeepaliveDOMRpcService(final DOMRpcService deviceRpc, final ResetKeepalive resetKeepaliveTask,
+ final long defaultRequestTimeoutMillis, final ScheduledExecutorService executor) {
this.deviceRpc = deviceRpc;
this.resetKeepaliveTask = resetKeepaliveTask;
+ this.defaultRequestTimeoutMillis = defaultRequestTimeoutMillis;
+ this.executor = executor;
}
@Nonnull
public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(@Nonnull final SchemaPath type, final NormalizedNode<?, ?> input) {
final CheckedFuture<DOMRpcResult, DOMRpcException> domRpcResultDOMRpcExceptionCheckedFuture = deviceRpc.invokeRpc(type, input);
Futures.addCallback(domRpcResultDOMRpcExceptionCheckedFuture, resetKeepaliveTask);
+
+ final RequestTimeoutTask timeoutTask = new RequestTimeoutTask(domRpcResultDOMRpcExceptionCheckedFuture);
+ executor.schedule(timeoutTask, defaultRequestTimeoutMillis, TimeUnit.MILLISECONDS);
+
return domRpcResultDOMRpcExceptionCheckedFuture;
}
public final class NetconfDeviceDataBroker implements DOMDataBroker {
private final RemoteDeviceId id;
private final NetconfBaseOps netconfOps;
- private final long requestTimeoutMillis;
private final boolean rollbackSupport;
private boolean candidateSupported;
private boolean runningWritable;
- public NetconfDeviceDataBroker(final RemoteDeviceId id, final SchemaContext schemaContext, final DOMRpcService rpc, final NetconfSessionPreferences netconfSessionPreferences, long requestTimeoutMillis) {
+ public NetconfDeviceDataBroker(final RemoteDeviceId id, final SchemaContext schemaContext, final DOMRpcService rpc, final NetconfSessionPreferences netconfSessionPreferences) {
this.id = id;
this.netconfOps = new NetconfBaseOps(rpc, schemaContext);
- this.requestTimeoutMillis = requestTimeoutMillis;
// get specific attributes from netconf preferences and get rid of it
// no need to keep the entire preferences object, its quite big with all the capability QNames
candidateSupported = netconfSessionPreferences.isCandidateSupported();
@Override
public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
- return new ReadOnlyTx(netconfOps, id, requestTimeoutMillis);
+ return new ReadOnlyTx(netconfOps, id);
}
@Override
public DOMDataWriteTransaction newWriteOnlyTransaction() {
if(candidateSupported) {
if(runningWritable) {
- return new WriteCandidateRunningTx(id, netconfOps, rollbackSupport, requestTimeoutMillis);
+ return new WriteCandidateRunningTx(id, netconfOps, rollbackSupport);
} else {
- return new WriteCandidateTx(id, netconfOps, rollbackSupport, requestTimeoutMillis);
+ return new WriteCandidateTx(id, netconfOps, rollbackSupport);
}
} else {
- return new WriteRunningTx(id, netconfOps, rollbackSupport, requestTimeoutMillis);
+ return new WriteRunningTx(id, netconfOps, rollbackSupport);
}
}
private final RemoteDeviceId id;
private final NetconfDeviceSalProvider salProvider;
- private final long defaultRequestTimeoutMillis;
private final List<AutoCloseable> salRegistrations = Lists.newArrayList();
- public NetconfDeviceSalFacade(final RemoteDeviceId id, final Broker domBroker, final BindingAwareBroker bindingBroker, long defaultRequestTimeoutMillis) {
+ public NetconfDeviceSalFacade(final RemoteDeviceId id, final Broker domBroker, final BindingAwareBroker bindingBroker) {
this.id = id;
this.salProvider = new NetconfDeviceSalProvider(id);
- this.defaultRequestTimeoutMillis = defaultRequestTimeoutMillis;
registerToSal(domBroker, bindingBroker);
}
public synchronized void onDeviceConnected(final SchemaContext schemaContext,
final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc) {
- final DOMDataBroker domBroker = new NetconfDeviceDataBroker(id, schemaContext, deviceRpc, netconfSessionPreferences, defaultRequestTimeoutMillis);
+ final DOMDataBroker domBroker = new NetconfDeviceDataBroker(id, schemaContext, deviceRpc, netconfSessionPreferences);
final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.MixinNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger LOG = LoggerFactory.getLogger(AbstractWriteTx.class);
- protected final long defaultRequestTimeoutMillis;
protected final RemoteDeviceId id;
protected final NetconfBaseOps netOps;
protected final boolean rollbackSupport;
// Allow commit to be called only once
protected boolean finished = false;
- public AbstractWriteTx(final long requestTimeoutMillis, final NetconfBaseOps netOps, final RemoteDeviceId id, final boolean rollbackSupport) {
- this.defaultRequestTimeoutMillis = requestTimeoutMillis;
+ public AbstractWriteTx(final NetconfBaseOps netOps, final RemoteDeviceId id, final boolean rollbackSupport) {
this.netOps = netOps;
this.id = id;
this.rollbackSupport = rollbackSupport;
}
protected abstract void editConfig(DataContainerChild<?, ?> editStructure, Optional<ModifyAction> defaultOperation) throws NetconfDocumentedException;
-
-
- protected ListenableFuture<DOMRpcResult> perfomRequestWithTimeout(String operation, ListenableFuture<DOMRpcResult> future) {
- try {
- future.get(defaultRequestTimeoutMillis, TimeUnit.MILLISECONDS);
- } catch (InterruptedException | ExecutionException e) {
- LOG.error("{}: {} failed with error", operation, id, e);
- return Futures.immediateFailedCheckedFuture(new RuntimeException(id + ": " + operation + " failed"));
- } catch (TimeoutException e) {
- LOG.warn("{}: Unable to {} after {} milliseconds", id, operation, defaultRequestTimeoutMillis, e);
- return Futures.immediateFailedCheckedFuture(new SchemaSourceException(e.getMessage()));
- }
- return future;
- }
}
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
private final RemoteDeviceId id;
private final FutureCallback<DOMRpcResult> loggingCallback;
- private final long requestTimeoutMillis;
-
- public ReadOnlyTx(final NetconfBaseOps netconfOps, final RemoteDeviceId id, final long requestTimeoutMillis) {
+ public ReadOnlyTx(final NetconfBaseOps netconfOps, final RemoteDeviceId id) {
this.netconfOps = netconfOps;
this.id = id;
- this.requestTimeoutMillis = requestTimeoutMillis;
// Simple logging callback to log result of read operation
loggingCallback = new FutureCallback<DOMRpcResult>() {
}
});
- if(!readWithTimeout("readConfigurationData", configRunning)) {
- return null;
- }
-
return MappingCheckedFuture.create(transformedFuture, ReadFailedException.MAPPER);
}
}
});
- if(!readWithTimeout("readOperationalData", configCandidate)) {
- return null;
- }
-
return MappingCheckedFuture.create(transformedFuture, ReadFailedException.MAPPER);
}
public Object getIdentifier() {
return this;
}
-
- private boolean readWithTimeout(String operation, ListenableFuture<DOMRpcResult> future) {
- try {
- future.get(requestTimeoutMillis, TimeUnit.MILLISECONDS);
- } catch (InterruptedException | ExecutionException e) {
- LOG.error("{}: {} failed with error", id, operation, e);
- throw new RuntimeException(id + ": readOperationalData failed");
- } catch (TimeoutException e) {
- LOG.warn("{}: Unable to {} after {} milliseconds", id, operation, requestTimeoutMillis, e);
- future.cancel(true);
- return false;
- }
- return true;
- }
}
private static final Logger LOG = LoggerFactory.getLogger(WriteCandidateRunningTx.class);
- public WriteCandidateRunningTx(final RemoteDeviceId id, final NetconfBaseOps netOps, final boolean rollbackSupport, final long requestTimeoutMillis) {
- super(id, netOps, rollbackSupport, requestTimeoutMillis);
+ public WriteCandidateRunningTx(final RemoteDeviceId id, final NetconfBaseOps netOps, final boolean rollbackSupport) {
+ super(id, netOps, rollbackSupport);
}
@Override
}
private void lockRunning() {
- final String operation = "Lock Running";
try {
- invokeBlocking(operation, new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
+ invokeBlocking("Lock running", new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
@Override
public ListenableFuture<DOMRpcResult> apply(final NetconfBaseOps input) {
- return perfomRequestWithTimeout(operation, input.lockRunning(new NetconfRpcFutureCallback(operation, id)));
-
+ return input.lockRunning(new NetconfRpcFutureCallback("Lock running", id));
}
});
} catch (final NetconfDocumentedException e) {
}
};
- public WriteCandidateTx(final RemoteDeviceId id, final NetconfBaseOps rpc, final boolean rollbackSupport, long requestTimeoutMillis) {
- super(requestTimeoutMillis, rpc, id, rollbackSupport);
+ public WriteCandidateTx(final RemoteDeviceId id, final NetconfBaseOps rpc, final boolean rollbackSupport) {
+ super(rpc, id, rollbackSupport);
}
@Override
}
private void lock() throws NetconfDocumentedException {
- final String operation = "Lock candidate";
try {
- invokeBlocking(operation, new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
+ invokeBlocking("Lock candidate", new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
@Override
public ListenableFuture<DOMRpcResult> apply(final NetconfBaseOps input) {
- return perfomRequestWithTimeout(operation, input.lockCandidate(new NetconfRpcFutureCallback(operation, id)));
+ return input.lockCandidate(new NetconfRpcFutureCallback("Lock candidate", id));
}
});
} catch (final NetconfDocumentedException e) {
@Override
protected void editConfig(final DataContainerChild<?, ?> editStructure, final Optional<ModifyAction> defaultOperation) throws NetconfDocumentedException {
- final String operation = "Edit candidate";
- invokeBlocking(operation, new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
+ invokeBlocking("Edit candidate", new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
@Override
public ListenableFuture<DOMRpcResult> apply(final NetconfBaseOps input) {
-
- return perfomRequestWithTimeout(operation, defaultOperation.isPresent()
- ? input.editConfigCandidate(new NetconfRpcFutureCallback(operation, id), editStructure, defaultOperation.get(),
- rollbackSupport)
- : input.editConfigCandidate(new NetconfRpcFutureCallback(operation, id), editStructure,
- rollbackSupport));
+ return defaultOperation.isPresent()
+ ? input.editConfigCandidate(new NetconfRpcFutureCallback("Edit candidate", id), editStructure, defaultOperation.get(),
+ rollbackSupport)
+ : input.editConfigCandidate(new NetconfRpcFutureCallback("Edit candidate", id), editStructure,
+ rollbackSupport);
}
});
}
private static final Logger LOG = LoggerFactory.getLogger(WriteRunningTx.class);
public WriteRunningTx(final RemoteDeviceId id, final NetconfBaseOps netOps,
- final boolean rollbackSupport, long requestTimeoutMillis) {
- super(requestTimeoutMillis, netOps, id, rollbackSupport);
+ final boolean rollbackSupport) {
+ super(netOps, id, rollbackSupport);
}
@Override
}
private void lock() {
- final String operation = "Lock running";
try {
- invokeBlocking(operation, new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
+ invokeBlocking("Lock running", new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
@Override
public ListenableFuture<DOMRpcResult> apply(final NetconfBaseOps input) {
- return perfomRequestWithTimeout(operation, input.lockRunning(new NetconfRpcFutureCallback(operation, id)));
+ return input.lockRunning(new NetconfRpcFutureCallback("Lock running", id));
}
});
} catch (final NetconfDocumentedException e) {
@Override
public synchronized CheckedFuture<Void, TransactionCommitFailedException> submit() {
- final ListenableFuture<Void> commitFutureAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
+ final ListenableFuture<Void> commmitFutureAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
@Override
public Void apply(final RpcResult<TransactionStatus> input) {
return null;
}
});
- return Futures.makeChecked(commitFutureAsVoid, new Function<Exception, TransactionCommitFailedException>() {
+ return Futures.makeChecked(commmitFutureAsVoid, new Function<Exception, TransactionCommitFailedException>() {
@Override
public TransactionCommitFailedException apply(final Exception input) {
return new TransactionCommitFailedException("Submit of transaction " + getIdentifier() + " failed", input);
@Override
protected void editConfig(final DataContainerChild<?, ?> editStructure, final Optional<ModifyAction> defaultOperation) throws NetconfDocumentedException {
- final String operation = "Edit running";
- invokeBlocking(operation, new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
+ invokeBlocking("Edit running", new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
@Override
public ListenableFuture<DOMRpcResult> apply(final NetconfBaseOps input) {
- return perfomRequestWithTimeout(operation, defaultOperation.isPresent()
- ? input.editConfigRunning(new NetconfRpcFutureCallback(operation, id), editStructure, defaultOperation.get(),
- rollbackSupport)
- : input.editConfigRunning(new NetconfRpcFutureCallback(operation, id), editStructure,
- rollbackSupport));
+ return defaultOperation.isPresent()
+ ? input.editConfigRunning(new NetconfRpcFutureCallback("Edit running", id), editStructure, defaultOperation.get(),
+ rollbackSupport)
+ : input.editConfigRunning(new NetconfRpcFutureCallback("Edit running", id), editStructure,
+ rollbackSupport);
}
});
}
private void unlock() {
- final String operation = "Unlocking running";
try {
- invokeBlocking(operation, new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
+ invokeBlocking("Unlocking running", new Function<NetconfBaseOps, ListenableFuture<DOMRpcResult>>() {
@Override
public ListenableFuture<DOMRpcResult> apply(final NetconfBaseOps input) {
- return perfomRequestWithTimeout(operation, input.unlockRunning(new NetconfRpcFutureCallback(operation, id)));
+ return input.unlockRunning(new NetconfRpcFutureCallback("Unlock running", id));
}
});
} catch (final NetconfDocumentedException e) {
doReturn(Futures.immediateCheckedFuture(result)).when(deviceRpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
final KeepaliveSalFacade keepaliveSalFacade =
- new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, executorServiceSpy, 1L);
+ new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, executorServiceSpy, 1L, 1L);
keepaliveSalFacade.setListener(listener);
keepaliveSalFacade.onDeviceConnected(null, null, deviceRpc);
.when(deviceRpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
final KeepaliveSalFacade keepaliveSalFacade =
- new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, executorServiceSpy, 1L);
+ new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, executorServiceSpy, 1L, 1L);
keepaliveSalFacade.setListener(listener);
keepaliveSalFacade.onDeviceConnected(null, null, deviceRpc);
.when(deviceRpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
final KeepaliveSalFacade keepaliveSalFacade =
- new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, executorServiceSpy, 100L);
+ new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, executorServiceSpy, 100L, 1L);
keepaliveSalFacade.setListener(listener);
keepaliveSalFacade.onDeviceConnected(null, null, deviceRpc);
private NetconfDeviceDataBroker getDataBroker(String... caps) {
NetconfSessionPreferences prefs = NetconfSessionPreferences.fromStrings(Arrays.asList(caps));
final RemoteDeviceId id = new RemoteDeviceId("device-1", InetSocketAddress.createUnresolved("localhost", 17830));
- return new NetconfDeviceDataBroker(id, schemaContext, rpcService, prefs, 1000);
+ return new NetconfDeviceDataBroker(id, schemaContext, rpcService, prefs);
}
}
\ No newline at end of file
@Test
public void testIgnoreNonVisibleData() {
final WriteCandidateTx tx = new WriteCandidateTx(id, new NetconfBaseOps(rpc, mock(SchemaContext.class)),
- false, 60000L);
+ false);
final MapNode emptyList = ImmutableNodes.mapNodeBuilder(NETCONF_FILTER_QNAME).build();
tx.merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(NETCONF_FILTER_QNAME)), emptyList);
tx.put(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(NETCONF_FILTER_QNAME)), emptyList);
@Test
public void testDiscardChanges() {
final WriteCandidateTx tx = new WriteCandidateTx(id, new NetconfBaseOps(rpc, mock(SchemaContext.class)),
- false, 60000L);
+ false);
final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = tx.submit();
try {
submitFuture.checkedGet();
.doReturn(rpcErrorFuture).when(rpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
final WriteCandidateTx tx = new WriteCandidateTx(id, new NetconfBaseOps(rpc, mock(SchemaContext.class)),
- false, 60000L);
+ false);
final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = tx.submit();
try {
.when(rpc).invokeRpc(any(SchemaPath.class), any(NormalizedNode.class));
final WriteRunningTx tx = new WriteRunningTx(id, new NetconfBaseOps(rpc, NetconfMessageTransformer.BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS.getSchemaContext()),
- false, 60000L);
+ false);
try {
tx.delete(LogicalDatastoreType.CONFIGURATION, yangIId);
} catch (final Exception e) {
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
import java.net.InetSocketAddress;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
-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.netconf.sal.connect.netconf.util.NetconfBaseOps;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-@PrepareForTest({NetconfBaseOps.class})
-@RunWith(PowerMockRunner.class)
public class ReadOnlyTxTest {
private static final YangInstanceIdentifier path = YangInstanceIdentifier.create();
public void testRead() throws Exception {
final NetconfBaseOps netconfOps = new NetconfBaseOps(rpc, mock(SchemaContext.class));
- final ReadOnlyTx readOnlyTx = new ReadOnlyTx(netconfOps, new RemoteDeviceId("a", new InetSocketAddress("localhost", 196)), 60000L);
+ final ReadOnlyTx readOnlyTx = new ReadOnlyTx(netconfOps, new RemoteDeviceId("a", new InetSocketAddress("localhost", 196)));
readOnlyTx.read(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create());
verify(rpc).invokeRpc(Mockito.eq(NetconfMessageTransformUtil.toPath(NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME)), any(NormalizedNode.class));
readOnlyTx.read(LogicalDatastoreType.OPERATIONAL, path);
verify(rpc).invokeRpc(Mockito.eq(NetconfMessageTransformUtil.toPath(NetconfMessageTransformUtil.NETCONF_GET_QNAME)), any(NormalizedNode.class));
}
-
- @SuppressWarnings("unchecked")
- @Test
- public void testReadTimeout() throws Exception {
- final ListenableFuture<DOMRpcResult> future = mock(ListenableFuture.class);
-
- Mockito.when(future.get(Mockito.anyLong(), any(TimeUnit.class))).then(new Answer<DOMRpcResult>() {
- @Override
- public DOMRpcResult answer(InvocationOnMock invocation)
- throws Throwable {
- throw new TimeoutException("Processing Timeout");
- }
- });
-
- final NetconfBaseOps netconfOps = PowerMockito.mock(NetconfBaseOps.class);
- Mockito.when(netconfOps.getConfigRunning(any(FutureCallback.class), any(Optional.class))).thenReturn(future);
-
-
- final ReadOnlyTx readOnlyTx = new ReadOnlyTx(netconfOps, new RemoteDeviceId("a", new InetSocketAddress("localhost", 196)), 100L);
- Assert.assertNull("Read operation didn't correctly timeout", readOnlyTx.read(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create()));
- readOnlyTx.close();
- }
}
\ No newline at end of file
final ExecutorService executorService = Executors.newFixedThreadPool(threadAmount);
LOG.info("Starting performance test");
+ boolean allThreadsCompleted = true;
final Stopwatch started = Stopwatch.createStarted();
try {
final List<Future<Void>> futures = executorService.invokeAll(callables, parameters.timeout, TimeUnit.MINUTES);
for (int i = 0; i < futures.size(); i++) {
Future<Void> future = futures.get(i);
if (future.isCancelled()) {
+ allThreadsCompleted = false;
LOG.info("{}. thread timed out.", i + 1);
} else {
try {
future.get();
} catch (final ExecutionException e) {
+ allThreadsCompleted = false;
LOG.info("{}. thread failed.", i + 1, e);
}
}
}
} catch (final InterruptedException e) {
+ allThreadsCompleted = false;
LOG.warn("Unable to execute requests", e);
}
executorService.shutdownNow();
started.stop();
LOG.info("FINISHED. Execution time: {}", started);
- LOG.info("Requests per second: {}", (parameters.editCount * 1000.0 / started.elapsed(TimeUnit.MILLISECONDS)));
-
+ // If some threads failed or timed out, skip calculation of requests per second value
+ // and do not log it
+ if(allThreadsCompleted) {
+ LOG.info("Requests per second: {}", (parameters.editCount * 1000.0 / started.elapsed(TimeUnit.MILLISECONDS)));
+ }
System.exit(0);
}
<dependency>
<groupId>net.java.dev.stax-utils</groupId>
<artifactId>stax-utils</artifactId>
- <version>20070216</version>
</dependency>
<dependency>
org.opendaylight.aaa.shiro.filters,
org.opendaylight.aaa.shiro.realm,
org.opendaylight.aaa.shiro.web.env,
+ org.opendaylight.aaa.filterchain.filters,
org.apache.shiro.web.env
</Import-Package>
- <Embed-Dependency>stax-utils</Embed-Dependency>
<Web-ContextPath>/restconf</Web-ContextPath>
</instructions>
</configuration>
<url-pattern>/*</url-pattern>
</filter-mapping>
+ <filter>
+ <filter-name>DynamicFilterChain</filter-name>
+ <filter-class>org.opendaylight.aaa.filterchain.filters.CustomFilterAdapter</filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>DynamicFilterChain</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+
<servlet-mapping>
<servlet-name>JAXRSRestconf</servlet-name>
<url-pattern>/*</url-pattern>