<feature version='${project.version}'>odl-netconf-mapping-api</feature>
<feature version='${project.version}'>odl-netconf-util</feature>
<feature version='${project.version}'>odl-netconf-netty-util</feature>
+ <feature version='${config.version}'>odl-config-netty</feature>
<!-- Netconf server without config connector is just an empty shell -->
<feature version='${project.version}'>odl-config-netconf-connector</feature>
<!-- Netconf will not provide schemas without monitoring -->
<feature version='${project.version}'>odl-netconf-netty-util</feature>
<bundle>mvn:org.opendaylight.netconf/netconf-impl/{{VERSION}}</bundle>
<feature version='${project.version}'>odl-netconf-notifications-api</feature>
+ <feature version='${config.version}'>odl-config-netty</feature>
<bundle>mvn:org.opendaylight.netconf/netconf-notifications-impl/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.netconf/config-netconf-connector/{{VERSION}}</bundle>
</feature>
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
+import java.util.Collection;
+import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
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.Sessions;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
-import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-final class MonitoringToMdsalWriter implements AutoCloseable, NetconfMonitoringService.MonitoringListener, BindingAwareProvider {
+/**
+ * Writes netconf server state changes received from NetconfMonitoringService to netconf-state datastore subtree.
+ */
+final class MonitoringToMdsalWriter implements AutoCloseable, NetconfMonitoringService.CapabilitiesListener,
+ NetconfMonitoringService.SessionsListener, BindingAwareProvider {
private static final Logger LOG = LoggerFactory.getLogger(MonitoringToMdsalWriter.class);
@Override
public void close() {
- deleteFromDatastore(InstanceIdentifier.create(NetconfState.class));
+ runTransaction((tx) -> tx.delete(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(NetconfState.class)));
}
@Override
public void onSessionStarted(Session session) {
final InstanceIdentifier<Session> sessionPath =
SESSIONS_INSTANCE_IDENTIFIER.child(Session.class, session.getKey());
- putToDatastore(sessionPath, session);
+ runTransaction((tx) -> tx.put(LogicalDatastoreType.OPERATIONAL, sessionPath, session));
}
@Override
public void onSessionEnded(Session session) {
final InstanceIdentifier<Session> sessionPath =
SESSIONS_INSTANCE_IDENTIFIER.child(Session.class, session.getKey());
- deleteFromDatastore(sessionPath);
+ runTransaction((tx) -> tx.delete(LogicalDatastoreType.OPERATIONAL, sessionPath));
+ }
+
+ @Override
+ public void onSessionsUpdated(Collection<Session> sessions) {
+ runTransaction((tx) -> updateSessions(tx, sessions));
}
@Override
public void onCapabilitiesChanged(Capabilities capabilities) {
- putToDatastore(CAPABILITIES_INSTANCE_IDENTIFIER, capabilities);
+ runTransaction((tx) -> tx.put(LogicalDatastoreType.OPERATIONAL, CAPABILITIES_INSTANCE_IDENTIFIER, capabilities));
}
@Override
public void onSchemasChanged(Schemas schemas) {
- putToDatastore(SCHEMAS_INSTANCE_IDENTIFIER, schemas);
+ runTransaction((tx) -> tx.put(LogicalDatastoreType.OPERATIONAL, SCHEMAS_INSTANCE_IDENTIFIER, schemas));
}
@Override
public void onSessionInitiated(final BindingAwareBroker.ProviderContext providerContext) {
dataBroker = providerContext.getSALService(DataBroker.class);
- serverMonitoringDependency.registerListener(this);
+ serverMonitoringDependency.registerCapabilitiesListener(this);
+ serverMonitoringDependency.registerSessionsListener(this);
}
- private <T extends DataObject> void putToDatastore(InstanceIdentifier<T> path, T value) {
+ private void runTransaction(Consumer<WriteTransaction> txUser) {
Preconditions.checkState(dataBroker != null);
final WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
- tx.put(LogicalDatastoreType.OPERATIONAL, path, value);
+ txUser.accept(tx);
Futures.addCallback(tx.submit(), new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void result) {
});
}
- private <T extends DataObject> void deleteFromDatastore(InstanceIdentifier<T> path) {
- Preconditions.checkState(dataBroker != null);
- final WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
- tx.delete(LogicalDatastoreType.OPERATIONAL, path);
- Futures.addCallback(tx.submit(), new FutureCallback<Void>() {
- @Override
- public void onSuccess(@Nullable Void result) {
- LOG.debug("Netconf state updated successfully");
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.warn("Unable to update netconf state", t);
- }
- });
+ private static void updateSessions(WriteTransaction tx, Collection<Session> sessions) {
+ for (Session session : sessions) {
+ final InstanceIdentifier<Session> sessionPath =
+ SESSIONS_INSTANCE_IDENTIFIER.child(Session.class, session.getKey());
+ tx.put(LogicalDatastoreType.OPERATIONAL, sessionPath, session);
+ }
}
}
import static org.mockito.Mockito.verify;
import com.google.common.util.concurrent.Futures;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- doReturn(null).when(monitoring).registerListener(any());
+ doReturn(null).when(monitoring).registerCapabilitiesListener(any());
+ doReturn(null).when(monitoring).registerSessionsListener(any());
doReturn(dataBroker).when(context).getSALService(DataBroker.class);
inOrder.verify(writeTransaction).submit();
}
+ @Test
+ public void testOnSessionsUpdated() throws Exception {
+ Session session1 = new SessionBuilder()
+ .setSessionId(1L)
+ .build();
+ Session session2 = new SessionBuilder()
+ .setSessionId(2L)
+ .build();
+ List<Session> sessions = new ArrayList<>();
+ sessions.add(session1);
+ sessions.add(session2);
+ final InstanceIdentifier<Session> id1 = InstanceIdentifier.create(NetconfState.class).child(Sessions.class).child(Session.class, session1.getKey());
+ final InstanceIdentifier<Session> id2 = InstanceIdentifier.create(NetconfState.class).child(Sessions.class).child(Session.class, session2.getKey());
+ writer.onSessionInitiated(context);
+ writer.onSessionsUpdated(sessions);
+ InOrder inOrder = inOrder(writeTransaction);
+ inOrder.verify(writeTransaction).put(LogicalDatastoreType.OPERATIONAL, id1, session1);
+ inOrder.verify(writeTransaction).put(LogicalDatastoreType.OPERATIONAL, id2, session2);
+ inOrder.verify(writeTransaction).submit();
+ }
+
@Test
public void testOnSessionInitiated() throws Exception {
writer.onSessionInitiated(context);
- verify(monitoring).registerListener(writer);
+ verify(monitoring).registerCapabilitiesListener(writer);
}
}
\ No newline at end of file
switch (modificationType) {
case WRITE:
final Session created = rootNode.getDataAfter();
- if (created != null) {
+ if (created != null && rootNode.getDataBefore() == null) {
publishStartedSession(created);
}
break;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import java.util.Collections;
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.NetconfSessionEnd;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStart;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.ZeroBasedCounter32;
public class SessionNotificationProducerTest {
Assert.assertEquals(session.getUsername(), value.getUsername());
}
+ @Test
+ public void testOnDataChangedSessionUpdated() throws Exception {
+ final DataTreeModification<Session> treeChange = mock(DataTreeModification.class);
+ final DataObjectModification<Session> changeObject = mock(DataObjectModification.class);
+ final Session sessionBefore = createSessionWithInRpcCount(1, 0);
+ final Session sessionAfter = createSessionWithInRpcCount(1, 1);
+ doReturn(sessionBefore).when(changeObject).getDataBefore();
+ doReturn(sessionAfter).when(changeObject).getDataAfter();
+ doReturn(DataObjectModification.ModificationType.WRITE).when(changeObject).getModificationType();
+ doReturn(changeObject).when(treeChange).getRootNode();
+ publisher.onDataTreeChanged(Collections.singleton(treeChange));
+ //session didn't start, only stats changed. No notification should be produced
+ verify(registration, never()).onSessionStarted(any());
+ verify(registration, never()).onSessionEnded(any());
+ }
+
@Test
public void testOnDataChangedSessionDeleted() throws Exception {
final Session session = createSession(1);
}
private Session createSession(long id) {
+ return createSessionWithInRpcCount(id, 0);
+ }
+
+ private Session createSessionWithInRpcCount(long id, long inRpc) {
return new SessionBuilder()
.setSessionId(id)
.setSourceHost(new Host("0.0.0.0".toCharArray()))
.setUsername("user")
+ .setInRpcs(new ZeroBasedCounter32(inRpc))
.build();
}
final DataObjectModification<Session> changeObject = mock(DataObjectModification.class);
switch (type) {
case WRITE:
+ doReturn(null).when(changeObject).getDataBefore();
doReturn(session).when(changeObject).getDataAfter();
break;
case DELETE:
package org.opendaylight.netconf.api.monitoring;
import com.google.common.base.Optional;
+import java.util.Collection;
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.Schemas;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
-public interface NetconfMonitoringService extends CapabilityListener, SessionListener {
+public interface NetconfMonitoringService {
Sessions getSessions();
+ /**
+ * Returns session monitoring service session listener, which is used to notify monitoring service about state of session.
+ * @return session listener
+ */
+ SessionListener getSessionListener();
+
Schemas getSchemas();
String getSchemaForCapability(String moduleName, Optional<String> revision);
Capabilities getCapabilities();
/**
- * Allows push based state information transfer. After the listener is registered, current state is pushed to the listener.
+ * Allows push based capabilities information transfer. After the listener is registered, current state is pushed to the listener.
* @param listener Monitoring listener
* @return listener registration
*/
- AutoCloseable registerListener(MonitoringListener listener);
+ AutoCloseable registerCapabilitiesListener(CapabilitiesListener listener);
+
+ /**
+ * Allows push based sessions information transfer.
+ * @param listener Monitoring listener
+ * @return listener registration
+ */
+ AutoCloseable registerSessionsListener(SessionsListener listener);
+
+ interface CapabilitiesListener {
+
+ /**
+ * Callback used to notify about a change in used capabilities
+ * @param capabilities resulting capabilities
+ */
+ void onCapabilitiesChanged(Capabilities capabilities);
+
+ /**
+ * Callback used to notify about a change in used schemas
+ * @param schemas resulting schemas
+ */
+ void onSchemasChanged(Schemas schemas);
+ }
- interface MonitoringListener {
+ interface SessionsListener {
/**
* Callback used to notify about netconf session start
* @param session started session
void onSessionEnded(Session session);
/**
- * Callback used to notify about a change in used capabilities
- * @param capabilities actual capabilities
+ * Callback used to notify about activity in netconf session, like
+ * rpc or notification. It is triggered at regular time interval. Session parameter
+ * contains only sessions which state was changed.
+ * @param sessions updated sessions
*/
- void onCapabilitiesChanged(Capabilities capabilities);
+ void onSessionsUpdated(Collection<Session> sessions);
- /**
- * Callback used to notify about a change in used schemas
- * @param schemas actual schemas
- */
- void onSchemasChanged(Schemas schemas);
}
}
--- /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.api.monitoring;
+
+/**
+ * Class represents change in netconf session.
+ */
+public class SessionEvent {
+ private final NetconfManagementSession session;
+ private final Type type;
+
+ private SessionEvent(NetconfManagementSession session, Type type) {
+ this.session = session;
+ this.type = type;
+ }
+
+ /**
+ * Returns session, where event occurred
+ * @return session
+ */
+ public NetconfManagementSession getSession() {
+ return session;
+ }
+
+ /**
+ * Returns event type
+ * @return type
+ */
+ public Type getType() {
+ return type;
+ }
+
+ public static SessionEvent inRpcSuccess(NetconfManagementSession session) {
+ return new SessionEvent(session, Type.IN_RPC_SUCCESS);
+ }
+
+ public static SessionEvent inRpcFail(NetconfManagementSession session) {
+ return new SessionEvent(session, Type.IN_RPC_FAIL);
+ }
+
+ public static SessionEvent outRpcError(NetconfManagementSession session) {
+ return new SessionEvent(session, Type.OUT_RPC_ERROR);
+ }
+
+ public static SessionEvent notification(NetconfManagementSession session) {
+ return new SessionEvent(session, Type.NOTIFICATION);
+ }
+
+ /**
+ * Session event type
+ */
+ public enum Type {
+
+ /**
+ * Correct rpc message received
+ */
+ IN_RPC_SUCCESS,
+
+ /**
+ * Incorrect rpc message received
+ */
+ IN_RPC_FAIL,
+
+ /**
+ * rpc-reply messages sent that contained an rpc-error element.
+ */
+ OUT_RPC_ERROR,
+
+ /**
+ * Notification message sent
+ */
+ NOTIFICATION
+ }
+}
* Created by mmarsale on 13.2.2015.
*/
public interface SessionListener {
+
+ /**
+ * Callback used to notify about netconf session start
+ * @param session started session
+ */
void onSessionUp(NetconfManagementSession session);
+ /**
+ * Callback used to notify about netconf session end
+ * @param session ended session
+ */
void onSessionDown(NetconfManagementSession session);
+
+ /**
+ * Callback used to notify about activity in netconf session, like
+ * rpc or notification
+ * @param event session event, contains session and type of event
+ */
+ void onSessionEvent(SessionEvent event);
}
<groupId>org.opendaylight.controller</groupId>
<artifactId>protocol-framework</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>threadpool-config-api</artifactId>
+ </dependency>
<!-- test dependencies -->
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
package org.opendaylight.controller.config.yang.config.netconf.northbound.impl;
+import com.google.common.base.Optional;
import org.opendaylight.netconf.impl.osgi.NetconfMonitoringServiceImpl;
public class NetconfServerMonitoringModule extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfServerMonitoringModule {
@Override
public java.lang.AutoCloseable createInstance() {
- return new NetconfMonitoringServiceImpl(getAggregatorDependency());
+ return new NetconfMonitoringServiceImpl(getAggregatorDependency(),
+ Optional.fromNullable(getScheduledThreadpoolDependency()),
+ getMonitoringUpdateInterval());
}
}
import org.opendaylight.netconf.nettyutil.AbstractNetconfSession;
import org.opendaylight.netconf.nettyutil.handler.NetconfMessageToXMLEncoder;
import org.opendaylight.netconf.nettyutil.handler.NetconfXMLToMessageDecoder;
+import org.opendaylight.netconf.notifications.NetconfNotification;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
private final NetconfHelloMessageAdditionalHeader header;
+ private final NetconfServerSessionListener sessionListener;
private ZonedDateTime loginTime;
- private long inRpcSuccess, inRpcFail, outRpcError;
+ private long inRpcSuccess, inRpcFail, outRpcError, outNotification;
private volatile boolean delayedClose;
public NetconfServerSession(final NetconfServerSessionListener sessionListener, final Channel channel, final long sessionId,
final NetconfHelloMessageAdditionalHeader header) {
super(sessionListener, channel, sessionId);
this.header = header;
+ this.sessionListener = sessionListener;
LOG.debug("Session {} created", toString());
}
@Override
public ChannelFuture sendMessage(final NetconfMessage netconfMessage) {
final ChannelFuture channelFuture = super.sendMessage(netconfMessage);
+ if (netconfMessage instanceof NetconfNotification) {
+ outNotification++;
+ sessionListener.onNotification(this, (NetconfNotification) netconfMessage);
+ }
// delayed close was set, close after the message was sent
if(delayedClose) {
channelFuture.addListener(new ChannelFutureListener() {
builder.setUsername(header.getUserName());
builder.setTransport(getTransportForString(header.getTransport()));
- builder.setOutNotifications(new ZeroBasedCounter32(0L));
+ builder.setOutNotifications(new ZeroBasedCounter32(outNotification));
builder.setKey(new SessionKey(getSessionId()));
import com.google.common.collect.ImmutableMap;
import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.opendaylight.controller.config.util.xml.XmlUtil;
-import org.opendaylight.netconf.util.messages.SendErrorExceptionUtil;
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.api.NetconfSessionListener;
import org.opendaylight.netconf.api.NetconfTerminationReason;
import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.netconf.api.monitoring.SessionEvent;
+import org.opendaylight.netconf.api.monitoring.SessionListener;
import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.netconf.impl.osgi.NetconfOperationRouter;
import org.opendaylight.netconf.util.messages.SubtreeFilter;
+import org.opendaylight.netconf.notifications.NetconfNotification;
+import org.opendaylight.netconf.util.messages.SendErrorExceptionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
public class NetconfServerSessionListener implements NetconfSessionListener<NetconfServerSession> {
private static final Logger LOG = LoggerFactory.getLogger(NetconfServerSessionListener.class);
- private final NetconfMonitoringService monitoringService;
+ private final SessionListener monitoringSessionListener;
private final NetconfOperationRouter operationRouter;
private final AutoCloseable onSessionDownCloseable;
public NetconfServerSessionListener(final NetconfOperationRouter operationRouter, final NetconfMonitoringService monitoringService,
final AutoCloseable onSessionDownCloseable) {
this.operationRouter = operationRouter;
- this.monitoringService = monitoringService;
+ this.monitoringSessionListener = monitoringService.getSessionListener();
this.onSessionDownCloseable = onSessionDownCloseable;
}
@Override
public void onSessionUp(final NetconfServerSession netconfNetconfServerSession) {
- monitoringService.onSessionUp(netconfNetconfServerSession);
- // FIXME monitoring service should be also notified about all the other changes to netconf session (from ietf-netconf-monitoring point of view)
- // This means also notifying after every message is processed
+ monitoringSessionListener.onSessionUp(netconfNetconfServerSession);
}
@Override
}
public void onDown(final NetconfServerSession netconfNetconfServerSession) {
- monitoringService.onSessionDown(netconfNetconfServerSession);
+ monitoringSessionListener.onSessionDown(netconfNetconfServerSession);
try {
operationRouter.close();
session);
LOG.debug("Responding with message {}", message);
session.sendMessage(message);
+ monitoringSessionListener.onSessionEvent(SessionEvent.inRpcSuccess(session));
} catch (final RuntimeException e) {
// TODO: should send generic error or close session?
LOG.error("Unexpected exception", e);
session.onIncommingRpcFail();
+ monitoringSessionListener.onSessionEvent(SessionEvent.inRpcFail(session));
throw new IllegalStateException("Unable to process incoming message " + netconfMessage, e);
} catch (DocumentedException e) {
LOG.trace("Error occurred while processing message",e);
session.onOutgoingRpcError();
session.onIncommingRpcFail();
+ monitoringSessionListener.onSessionEvent(SessionEvent.inRpcFail(session));
+ monitoringSessionListener.onSessionEvent(SessionEvent.outRpcError(session));
SendErrorExceptionUtil.sendErrorMessage(session, e, netconfMessage);
}
}
+ public void onNotification(final NetconfServerSession session, final NetconfNotification notification) {
+ monitoringSessionListener.onSessionEvent(SessionEvent.notification(session));
+ }
+
private NetconfMessage processDocument(final NetconfMessage netconfMessage, final NetconfServerSession session)
throws DocumentedException {
--- /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.impl.osgi;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+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.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.Yang;
+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.SchemasBuilder;
+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.schemas.SchemaBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.SchemaKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChangeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.changed.by.parms.ChangedByBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.changed.by.parms.changed.by.server.or.user.ServerBuilder;
+
+class NetconfCapabilityMonitoringService implements CapabilityListener, AutoCloseable {
+
+ private static final Schema.Location NETCONF_LOCATION = new Schema.Location(Schema.Location.Enumeration.NETCONF);
+ private static final List<Schema.Location> NETCONF_LOCATIONS = ImmutableList.of(NETCONF_LOCATION);
+ private static final BasicCapability CANDIDATE_CAPABILITY = new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0");
+ private static final Function<Capability, Uri> CAPABILITY_TO_URI = new Function<Capability, Uri>() {
+ @Override
+ public Uri apply(final Capability input) {
+ return new Uri(input.getCapabilityUri());
+ }
+ };
+
+ 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<NetconfMonitoringService.CapabilitiesListener> listeners = Sets.newHashSet();
+ private volatile BaseNotificationPublisherRegistration notificationPublisher;
+
+ NetconfCapabilityMonitoringService(final NetconfOperationServiceFactory netconfOperationProvider) {
+ this.netconfOperationProvider = netconfOperationProvider;
+ netconfOperationProvider.registerCapabilityListener(this);
+ }
+
+ synchronized Schemas getSchemas() {
+ try {
+ return transformSchemas(netconfOperationProvider.getCapabilities());
+ } catch (final RuntimeException e) {
+ throw e;
+ } catch (final Exception e) {
+ throw new IllegalStateException("Exception while closing", e);
+ }
+ }
+
+ synchronized String getSchemaForModuleRevision(final String moduleName, final Optional<String> revision) {
+
+ Map<String, String> revisionMapRequest = mappedModulesToRevisionToSchema.get(moduleName);
+ Preconditions.checkState(revisionMapRequest != null, "Capability for module %s not present, " + ""
+ + "available modules : %s", moduleName, Collections2.transform(capabilities.values(), CAPABILITY_TO_URI));
+
+ if (revision.isPresent()) {
+ String schema = revisionMapRequest.get(revision.get());
+
+ Preconditions.checkState(schema != null,
+ "Capability for module %s:%s not present, available revisions for module: %s", moduleName,
+ revision.get(), revisionMapRequest.keySet());
+
+ return schema;
+ } else {
+ Preconditions.checkState(revisionMapRequest.size() == 1,
+ "Expected 1 capability for module %s, available revisions : %s", moduleName,
+ revisionMapRequest.keySet());
+ //Only one revision is present, so return it
+ return revisionMapRequest.values().iterator().next();
+ }
+ }
+
+ private 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 static boolean isValidModuleCapability(Capability cap) {
+ return cap.getModuleName().isPresent()
+ && cap.getRevision().isPresent()
+ && cap.getCapabilitySchema().isPresent();
+ }
+
+
+ synchronized Capabilities getCapabilities() {
+ return new CapabilitiesBuilder().setCapability(Lists.newArrayList(capabilities.keySet())).build();
+ }
+
+ synchronized AutoCloseable registerListener(final NetconfMonitoringService.CapabilitiesListener listener) {
+ listeners.add(listener);
+ listener.onCapabilitiesChanged(getCapabilities());
+ listener.onSchemasChanged(getSchemas());
+ return new AutoCloseable() {
+ @Override
+ public void close() throws Exception {
+ synchronized (NetconfCapabilityMonitoringService.this) {
+ listeners.remove(listener);
+ }
+ }
+ };
+ }
+
+ private static Schemas transformSchemas(final Set<Capability> caps) {
+ final List<Schema> schemas = new ArrayList<>(caps.size());
+ for (final Capability cap : caps) {
+ if (cap.getCapabilitySchema().isPresent()) {
+ final SchemaBuilder builder = new SchemaBuilder();
+
+ Preconditions.checkState(isValidModuleCapability(cap));
+
+ builder.setNamespace(new Uri(cap.getModuleNamespace().get()));
+
+ final String version = cap.getRevision().get();
+ builder.setVersion(version);
+
+ final String identifier = cap.getModuleName().get();
+ builder.setIdentifier(identifier);
+
+ builder.setFormat(Yang.class);
+
+ builder.setLocation(transformLocations(cap.getLocation()));
+
+ builder.setKey(new SchemaKey(Yang.class, identifier, version));
+
+ schemas.add(builder.build());
+ }
+ }
+
+ return new SchemasBuilder().setSchema(schemas).build();
+ }
+
+ private static List<Schema.Location> transformLocations(final Collection<String> locations) {
+ if (locations.isEmpty()) {
+ return NETCONF_LOCATIONS;
+ }
+
+ final Builder<Schema.Location> b = ImmutableList.builder();
+ b.add(NETCONF_LOCATION);
+
+ for (final String location : locations) {
+ b.add(new Schema.Location(new Uri(location)));
+ }
+
+ return b.build();
+ }
+
+ private static Set<Capability> setupCapabilities(final Set<Capability> caps) {
+ Set<Capability> capabilities = new HashSet<>(caps);
+ capabilities.add(CANDIDATE_CAPABILITY);
+ // TODO rollback on error not supported EditConfigXmlParser:100
+ // [RFC6241] 8.5. Rollback-on-Error Capability
+ // capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
+ return capabilities;
+ }
+
+ @Override
+ public synchronized void close() throws Exception {
+ listeners.clear();
+ sessions.clear();
+ capabilities.clear();
+ }
+
+ @Override
+ public synchronized void onCapabilitiesChanged(Set<Capability> added, Set<Capability> removed) {
+ onCapabilitiesAdded(added);
+ onCapabilitiesRemoved(removed);
+ updateCapabilityToSchemaMap(added, removed);
+ notifyCapabilityChanged(getCapabilities());
+
+ // publish notification to notification collector about changed capabilities
+ if (notificationPublisher != null) {
+ notificationPublisher.onCapabilityChanged(computeDiff(added, removed));
+ }
+ }
+
+ private void notifyCapabilityChanged(Capabilities capabilities) {
+ for (NetconfMonitoringService.CapabilitiesListener listener : listeners) {
+ listener.onCapabilitiesChanged(capabilities);
+ listener.onSchemasChanged(getSchemas());
+ }
+ }
+
+
+ private static NetconfCapabilityChange computeDiff(final Set<Capability> added, final Set<Capability> removed) {
+ final NetconfCapabilityChangeBuilder netconfCapabilityChangeBuilder = new NetconfCapabilityChangeBuilder();
+ netconfCapabilityChangeBuilder.setChangedBy(new ChangedByBuilder().setServerOrUser(new ServerBuilder().setServer(true).build()).build());
+ netconfCapabilityChangeBuilder.setDeletedCapability(Lists.newArrayList(Collections2.transform(removed, CAPABILITY_TO_URI)));
+ netconfCapabilityChangeBuilder.setAddedCapability(Lists.newArrayList(Collections2.transform(added, CAPABILITY_TO_URI)));
+ // TODO modified should be computed ... but why ?
+ netconfCapabilityChangeBuilder.setModifiedCapability(Collections.<Uri>emptyList());
+ return netconfCapabilityChangeBuilder.build();
+ }
+
+
+ private void onCapabilitiesAdded(final Set<Capability> addedCaps) {
+ this.capabilities.putAll(Maps.uniqueIndex(setupCapabilities(addedCaps), CAPABILITY_TO_URI));
+ }
+
+ private void onCapabilitiesRemoved(final Set<Capability> removedCaps) {
+ for (final Capability addedCap : removedCaps) {
+ capabilities.remove(CAPABILITY_TO_URI.apply(addedCap));
+ }
+ }
+
+ void setNotificationPublisher(final BaseNotificationPublisherRegistration notificationPublisher) {
+ this.notificationPublisher = notificationPublisher;
+ }
+}
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * 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,
*/
package org.opendaylight.netconf.impl.osgi;
-import com.google.common.base.Function;
import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.config.util.capability.BasicCapability;
-import org.opendaylight.controller.config.util.capability.Capability;
-import org.opendaylight.netconf.api.monitoring.NetconfManagementSession;
+import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.netconf.api.monitoring.SessionListener;
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.Yang;
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.SchemasBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SessionsBuilder;
-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.schemas.SchemaBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.SchemaKey;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChangeBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.changed.by.parms.ChangedByBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.changed.by.parms.changed.by.server.or.user.ServerBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
public class NetconfMonitoringServiceImpl implements NetconfMonitoringService, AutoCloseable {
- private static final Schema.Location NETCONF_LOCATION = new Schema.Location(Schema.Location.Enumeration.NETCONF);
- private static final List<Schema.Location> NETCONF_LOCATIONS = ImmutableList.of(NETCONF_LOCATION);
- private static final Logger LOG = LoggerFactory.getLogger(NetconfMonitoringServiceImpl.class);
- private static final Function<NetconfManagementSession, Session> SESSION_FUNCTION = new Function<NetconfManagementSession, Session>() {
- @Override
- public Session apply(@Nonnull final NetconfManagementSession input) {
- return input.toManagementSession();
- }
- };
- private static final Function<Capability, Uri> CAPABILITY_TO_URI = new Function<Capability, Uri>() {
- @Override
- public Uri apply(final Capability input) {
- return new Uri(input.getCapabilityUri());
- }
- };
+ private final NetconfCapabilityMonitoringService capabilityMonitoring;
+ private final NetconfSessionMonitoringService sessionMonitoring;
- 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;
-
- public NetconfMonitoringServiceImpl(final NetconfOperationServiceFactory netconfOperationProvider) {
- this.netconfOperationProvider = netconfOperationProvider;
- netconfOperationProvider.registerCapabilityListener(this);
+ public NetconfMonitoringServiceImpl(NetconfOperationServiceFactory opProvider) {
+ this(opProvider, Optional.absent(), 0);
}
- @Override
- public synchronized void onSessionUp(final NetconfManagementSession session) {
- LOG.debug("Session {} up", session);
- Preconditions.checkState(!sessions.contains(session), "Session %s was already added", session);
- sessions.add(session);
- notifySessionUp(session);
- }
+ public NetconfMonitoringServiceImpl(NetconfOperationServiceFactory opProvider,
+ Optional<ScheduledThreadPool> threadPool,
+ long updateInterval) {
+ this.capabilityMonitoring = new NetconfCapabilityMonitoringService(opProvider);
+ this.sessionMonitoring = new NetconfSessionMonitoringService(threadPool, updateInterval);
- @Override
- public synchronized void onSessionDown(final NetconfManagementSession session) {
- LOG.debug("Session {} down", session);
- Preconditions.checkState(sessions.contains(session), "Session %s not present", session);
- sessions.remove(session);
- notifySessionDown(session);
}
@Override
- public synchronized Sessions getSessions() {
- return new SessionsBuilder().setSession(ImmutableList.copyOf(Collections2.transform(sessions, SESSION_FUNCTION))).build();
+ public Sessions getSessions() {
+ return sessionMonitoring.getSessions();
}
@Override
- public synchronized Schemas getSchemas() {
- try {
- return transformSchemas(netconfOperationProvider.getCapabilities());
- } catch (final RuntimeException e) {
- throw e;
- } catch (final Exception e) {
- throw new IllegalStateException("Exception while closing", e);
- }
+ public SessionListener getSessionListener() {
+ return sessionMonitoring;
}
@Override
- public synchronized String getSchemaForCapability(final String moduleName, final Optional<String> revision) {
-
- Map<String, String> revisionMapRequest = mappedModulesToRevisionToSchema.get(moduleName);
- Preconditions.checkState(revisionMapRequest != null, "Capability for module %s not present, " + ""
- + "available modules : %s", moduleName, Collections2.transform(capabilities.values(), CAPABILITY_TO_URI));
-
- if (revision.isPresent()) {
- String schema = revisionMapRequest.get(revision.get());
-
- Preconditions.checkState(schema != null,
- "Capability for module %s:%s not present, available revisions for module: %s", moduleName,
- revision.get(), revisionMapRequest.keySet());
-
- return schema;
- } else {
- Preconditions.checkState(revisionMapRequest.size() == 1,
- "Expected 1 capability for module %s, available revisions : %s", moduleName,
- revisionMapRequest.keySet());
- return revisionMapRequest.values().iterator().next();
- }
- }
-
- 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();
+ public Schemas getSchemas() {
+ return capabilityMonitoring.getSchemas();
}
@Override
- public synchronized Capabilities getCapabilities() {
- return new CapabilitiesBuilder().setCapability(Lists.newArrayList(capabilities.keySet())).build();
+ public String getSchemaForCapability(String moduleName, Optional<String> revision) {
+ return capabilityMonitoring.getSchemaForModuleRevision(moduleName, revision);
}
@Override
- public synchronized AutoCloseable registerListener(final MonitoringListener listener) {
- listeners.add(listener);
- listener.onCapabilitiesChanged(getCapabilities());
- listener.onSchemasChanged(getSchemas());
- return new AutoCloseable() {
- @Override
- public void close() throws Exception {
- listeners.remove(listener);
- }
- };
- }
-
- private static Schemas transformSchemas(final Set<Capability> caps) {
- final List<Schema> schemas = new ArrayList<>(caps.size());
- for (final Capability cap : caps) {
- if (cap.getCapabilitySchema().isPresent()) {
- final SchemaBuilder builder = new SchemaBuilder();
- Preconditions.checkState(cap.getModuleNamespace().isPresent());
- builder.setNamespace(new Uri(cap.getModuleNamespace().get()));
-
- Preconditions.checkState(cap.getRevision().isPresent());
- final String version = cap.getRevision().get();
- builder.setVersion(version);
-
- Preconditions.checkState(cap.getModuleName().isPresent());
- final String identifier = cap.getModuleName().get();
- builder.setIdentifier(identifier);
-
- builder.setFormat(Yang.class);
-
- builder.setLocation(transformLocations(cap.getLocation()));
-
- builder.setKey(new SchemaKey(Yang.class, identifier, version));
-
- schemas.add(builder.build());
- }
- }
-
- return new SchemasBuilder().setSchema(schemas).build();
- }
-
- private static List<Schema.Location> transformLocations(final Collection<String> locations) {
- if (locations.isEmpty()) {
- return NETCONF_LOCATIONS;
- }
-
- final Builder<Schema.Location> b = ImmutableList.builder();
- b.add(NETCONF_LOCATION);
-
- for (final String location : locations) {
- b.add(new Schema.Location(new Uri(location)));
- }
-
- return b.build();
- }
-
- public static Set<Capability> setupCapabilities(final Set<Capability> caps) {
- Set<Capability> capabilities = new HashSet<>(caps);
- capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
- // TODO rollback on error not supported EditConfigXmlParser:100
- // [RFC6241] 8.5. Rollback-on-Error Capability
- // capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
- return capabilities;
+ public Capabilities getCapabilities() {
+ return capabilityMonitoring.getCapabilities();
}
@Override
- public synchronized void close() throws Exception {
- listeners.clear();
- sessions.clear();
- capabilities.clear();
+ public AutoCloseable registerCapabilitiesListener(CapabilitiesListener listener) {
+ return capabilityMonitoring.registerListener(listener);
}
@Override
- public void onCapabilitiesChanged(Set<Capability> added, Set<Capability> removed) {
- onCapabilitiesAdded(added);
- onCapabilitiesRemoved(removed);
- updateCapabilityToSchemaMap(added, removed);
- notifyCapabilityChanged(getCapabilities());
-
- // publish notification to notification collector about changed capabilities
- if (notificationPublisher != null) {
- notificationPublisher.onCapabilityChanged(computeDiff(added, removed));
- }
- }
-
- private void notifyCapabilityChanged(Capabilities capabilities) {
- for (MonitoringListener listener : listeners) {
- listener.onCapabilitiesChanged(capabilities);
- listener.onSchemasChanged(getSchemas());
- }
- }
-
- private void notifySessionUp(NetconfManagementSession managementSession) {
- Session session = SESSION_FUNCTION.apply(managementSession);
- for (MonitoringListener listener : listeners) {
- listener.onSessionStarted(session);
- }
+ public AutoCloseable registerSessionsListener(SessionsListener listener) {
+ return sessionMonitoring.registerListener(listener);
}
- private void notifySessionDown(NetconfManagementSession managementSession) {
- Session session = SESSION_FUNCTION.apply(managementSession);
- for (MonitoringListener listener : listeners) {
- listener.onSessionEnded(session);
- }
+ public void setNotificationPublisher(BaseNotificationPublisherRegistration notificationPublisher) {
+ this.capabilityMonitoring.setNotificationPublisher(notificationPublisher);
}
- static NetconfCapabilityChange computeDiff(final Set<Capability> added, final Set<Capability> removed) {
- final NetconfCapabilityChangeBuilder netconfCapabilityChangeBuilder = new NetconfCapabilityChangeBuilder();
- netconfCapabilityChangeBuilder.setChangedBy(new ChangedByBuilder().setServerOrUser(new ServerBuilder().setServer(true).build()).build());
- netconfCapabilityChangeBuilder.setDeletedCapability(Lists.newArrayList(Collections2.transform(removed, CAPABILITY_TO_URI)));
- netconfCapabilityChangeBuilder.setAddedCapability(Lists.newArrayList(Collections2.transform(added, CAPABILITY_TO_URI)));
- // TODO modified should be computed ... but why ?
- netconfCapabilityChangeBuilder.setModifiedCapability(Collections.<Uri>emptyList());
- return netconfCapabilityChangeBuilder.build();
- }
-
-
- private synchronized void onCapabilitiesAdded(final Set<Capability> addedCaps) {
- this.capabilities.putAll(Maps.uniqueIndex(setupCapabilities(addedCaps), CAPABILITY_TO_URI));
- }
-
- private synchronized void onCapabilitiesRemoved(final Set<Capability> addedCaps) {
- for (final Capability addedCap : addedCaps) {
- capabilities.remove(CAPABILITY_TO_URI.apply(addedCap));
- }
- }
-
- public void setNotificationPublisher(final BaseNotificationPublisherRegistration notificationPublisher) {
- this.notificationPublisher = notificationPublisher;
+ @Override
+ public void close() throws Exception {
+ capabilityMonitoring.close();
+ sessionMonitoring.close();
}
}
--- /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.impl.osgi;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
+import org.opendaylight.netconf.api.monitoring.NetconfManagementSession;
+import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.netconf.api.monitoring.SessionEvent;
+import org.opendaylight.netconf.api.monitoring.SessionListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SessionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class implements {@link SessionListener} to receive updates about Netconf sessions. Instance notifies its listeners
+ * about session start and end. It also publishes on regular interval list of sessions,
+ * where events like rpc or notification happened.
+ */
+class NetconfSessionMonitoringService implements SessionListener, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfSessionMonitoringService.class);
+
+ private final Set<NetconfManagementSession> sessions = Sets.newHashSet();
+ private final Set<NetconfManagementSession> changedSessions = Sets.newHashSet();
+ private final Set<NetconfMonitoringService.SessionsListener> listeners = Sets.newHashSet();
+ private final ScheduledExecutorService executor;
+ private final long updateInterval;
+ private boolean running;
+
+ /**
+ * @param schedulingThreadPool thread pool for scheduling session stats updates. If not present, updates won't be scheduled.
+ * @param updateInterval update interval. If is less than 0, updates won't be scheduled
+ */
+ NetconfSessionMonitoringService(Optional<ScheduledThreadPool> schedulingThreadPool, long updateInterval) {
+ this.updateInterval = updateInterval;
+ if (schedulingThreadPool.isPresent() && updateInterval > 0) {
+ this.executor = schedulingThreadPool.get().getExecutor();
+ LOG.info("/netconf-state/sessions will be updated every {} seconds.", updateInterval);
+ } else {
+ LOG.info("Scheduling thread pool is present = {}, update interval {}: /netconf-state/sessions won't be updated.",
+ schedulingThreadPool.isPresent(), updateInterval);
+ this.executor = null;
+ }
+ }
+
+ synchronized Sessions getSessions() {
+ final Collection<Session> managementSessions = Collections2.transform(sessions, NetconfManagementSession::toManagementSession);
+ return new SessionsBuilder().setSession(ImmutableList.copyOf(managementSessions)).build();
+ }
+
+ @Override
+ public synchronized void onSessionUp(final NetconfManagementSession session) {
+ LOG.debug("Session {} up", session);
+ Preconditions.checkState(!sessions.contains(session), "Session %s was already added", session);
+ sessions.add(session);
+ notifySessionUp(session);
+ }
+
+ @Override
+ public synchronized void onSessionDown(final NetconfManagementSession session) {
+ LOG.debug("Session {} down", session);
+ Preconditions.checkState(sessions.contains(session), "Session %s not present", session);
+ sessions.remove(session);
+ changedSessions.remove(session);
+ notifySessionDown(session);
+ }
+
+ @Override
+ public synchronized void onSessionEvent(SessionEvent event) {
+ changedSessions.add(event.getSession());
+ }
+
+ synchronized AutoCloseable registerListener(final NetconfMonitoringService.SessionsListener listener) {
+ listeners.add(listener);
+ if (!running) {
+ startUpdateSessionStats();
+ }
+ return new AutoCloseable() {
+ @Override
+ public void close() throws Exception {
+ listeners.remove(listener);
+ }
+ };
+ }
+
+ @Override
+ public synchronized void close() throws Exception {
+ stopUpdateSessionStats();
+ listeners.clear();
+ sessions.clear();
+ }
+
+ private synchronized void updateSessionStats() {
+ if (changedSessions.isEmpty()) {
+ return;
+ }
+ final List<Session> changed = changedSessions.stream()
+ .map(NetconfManagementSession::toManagementSession)
+ .collect(Collectors.toList());
+ final ImmutableList<Session> sessionImmutableList = ImmutableList.copyOf(changed);
+ for (NetconfMonitoringService.SessionsListener listener : listeners) {
+ listener.onSessionsUpdated(sessionImmutableList);
+ }
+ changedSessions.clear();
+ }
+
+ private void notifySessionUp(NetconfManagementSession managementSession) {
+ Session session = managementSession.toManagementSession();
+ for (NetconfMonitoringService.SessionsListener listener : listeners) {
+ listener.onSessionStarted(session);
+ }
+ }
+
+ private void notifySessionDown(NetconfManagementSession managementSession) {
+ Session session = managementSession.toManagementSession();
+ for (NetconfMonitoringService.SessionsListener listener : listeners) {
+ listener.onSessionEnded(session);
+ }
+ }
+
+ private void startUpdateSessionStats() {
+ if (executor != null) {
+ executor.scheduleAtFixedRate(this::updateSessionStats, 1, updateInterval, TimeUnit.SECONDS);
+ running = true;
+ }
+ }
+
+ private void stopUpdateSessionStats() {
+ if (executor != null) {
+ executor.shutdownNow();
+ running = false;
+ }
+ }
+}
import netconf-northbound-mapper { prefix nnm; revision-date 2015-01-14; }
import netconf-northbound { prefix nn; revision-date 2015-01-14; }
import netty {prefix netty; }
+ import threadpool {prefix th;}
description
"This module contains the base YANG definitions for
}
}
}
+ container scheduled-threadpool {
+ uses config:service-ref {
+ refine type {
+ mandatory false;
+ config:required-identity th:scheduled-threadpool;
+ }
+ }
+ description "Dedicated to update netconf-state/sessions subtree on session change.";
+ }
+ leaf monitoring-update-interval {
+ description "Specifies interval in seconds after which session stats are updated. If zero, stats won't be updated.";
+ type uint32;
+ default 0;
+ }
}
}
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anySetOf;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import org.opendaylight.controller.config.util.capability.Capability;
import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.netconf.api.monitoring.SessionEvent;
+import org.opendaylight.netconf.api.monitoring.SessionListener;
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
import org.opendaylight.netconf.api.monitoring.CapabilityListener;
public static NetconfMonitoringService createMockedMonitoringService() {
NetconfMonitoringService monitoring = mock(NetconfMonitoringService.class);
- doNothing().when(monitoring).onSessionUp(any(NetconfServerSession.class));
- doNothing().when(monitoring).onSessionDown(any(NetconfServerSession.class));
+ final SessionListener sessionListener = mock(SessionListener.class);
+ doNothing().when(sessionListener).onSessionUp(any(NetconfServerSession.class));
+ doNothing().when(sessionListener).onSessionDown(any(NetconfServerSession.class));
+ doNothing().when(sessionListener).onSessionEvent(any(SessionEvent.class));
doReturn(new AutoCloseable() {
@Override
public void close() throws Exception {
}
- }).when(monitoring).registerListener(any(NetconfMonitoringService.MonitoringListener.class));
- doNothing().when(monitoring).onCapabilitiesChanged(anySetOf(Capability.class), anySetOf(Capability.class));
+ }).when(monitoring).registerCapabilitiesListener(any(NetconfMonitoringService.CapabilitiesListener.class));
+ doReturn(sessionListener).when(monitoring).getSessionListener();
doReturn(new CapabilitiesBuilder().setCapability(Collections.<Uri>emptyList()).build()).when(monitoring).getCapabilities();
return monitoring;
}
import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
import org.opendaylight.yangtools.yang.model.api.Module;
-public class NetconfMonitoringServiceImplTest {
+public class NetconfCapabilityMonitoringServiceTest {
private static final String TEST_MODULE_CONTENT = "content";
private static final String TEST_MODULE_CONTENT2 = "content2";
@Mock
private NetconfManagementSession sessionMock;
@Mock
- private NetconfMonitoringService.MonitoringListener listener;
+ private NetconfMonitoringService.CapabilitiesListener listener;
@Mock
private BaseNotificationPublisherRegistration notificationPublisher;
- private NetconfMonitoringServiceImpl monitoringService;
+ private NetconfCapabilityMonitoringService monitoringService;
@BeforeClass
public static void suiteSetUp() throws Exception {
CAPABILITIES.add(new BasicCapability("urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24"));
doReturn(CAPABILITIES).when(operationServiceFactoryMock).getCapabilities();
- doReturn(null).when(operationServiceFactoryMock).registerCapabilityListener(any(NetconfMonitoringServiceImpl.class));
+ doReturn(null).when(operationServiceFactoryMock).registerCapabilityListener(any(NetconfCapabilityMonitoringService.class));
doReturn(SESSION).when(sessionMock).toManagementSession();
doNothing().when(listener).onCapabilitiesChanged(any());
doNothing().when(listener).onSchemasChanged(any());
- doNothing().when(listener).onSessionStarted(any());
- doNothing().when(listener).onSessionEnded(any());
doNothing().when(notificationPublisher).onCapabilityChanged(any());
doNothing().when(notificationPublisher).onSessionStarted(any());
doNothing().when(notificationPublisher).onSessionEnded(any());
- monitoringService = new NetconfMonitoringServiceImpl(operationServiceFactoryMock);
+ monitoringService = new NetconfCapabilityMonitoringService(operationServiceFactoryMock);
monitoringService.onCapabilitiesChanged(CAPABILITIES, Collections.emptySet());
monitoringService.setNotificationPublisher(notificationPublisher);
monitoringService.registerListener(listener);
@Test
public void testListeners() throws Exception {
- monitoringService.onSessionUp(sessionMock);
HashSet<Capability> added = new HashSet<>();
added.add(new BasicCapability("toAdd"));
monitoringService.onCapabilitiesChanged(added, Collections.emptySet());
- monitoringService.onSessionDown(sessionMock);
- verify(listener).onSessionStarted(any());
- verify(listener).onSessionEnded(any());
//onCapabilitiesChanged and onSchemasChanged are invoked also after listener registration
verify(listener, times(2)).onCapabilitiesChanged(any());
verify(listener, times(2)).onSchemasChanged(any());
public void testGetSchemaForCapability() throws Exception {
//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));
+ final String schema = monitoringService.getSchemaForModuleRevision(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));
+ final String schema2 = monitoringService.getSchemaForModuleRevision(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());
+ final String schema3 = monitoringService.getSchemaForModuleRevision(TEST_MODULE_NAME, Optional.absent());
Assert.assertEquals(TEST_MODULE_CONTENT2, schema3);
}
@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());
}
Assert.assertEquals(Collections.emptySet(), new HashSet<>(afterRemove.getAddedCapability()));
}
- @Test
- public void testOnSessionUpAndDown() throws Exception {
- monitoringService.onSessionUp(sessionMock);
- ArgumentCaptor<Session> sessionUpCaptor = ArgumentCaptor.forClass(Session.class);
- verify(listener).onSessionStarted(sessionUpCaptor.capture());
- final Session sesionUp = sessionUpCaptor.getValue();
- Assert.assertEquals(SESSION.getSessionId(), sesionUp.getSessionId());
- Assert.assertEquals(SESSION.getSourceHost(), sesionUp.getSourceHost());
- Assert.assertEquals(SESSION.getUsername(), sesionUp.getUsername());
-
- monitoringService.onSessionDown(sessionMock);
- ArgumentCaptor<Session> sessionDownCaptor = ArgumentCaptor.forClass(Session.class);
- verify(listener).onSessionEnded(sessionDownCaptor.capture());
- final Session sessionDown = sessionDownCaptor.getValue();
- Assert.assertEquals(SESSION.getSessionId(), sessionDown.getSessionId());
- Assert.assertEquals(SESSION.getSourceHost(), sessionDown.getSourceHost());
- Assert.assertEquals(SESSION.getUsername(), sessionDown.getUsername());
- }
}
--- /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.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.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.base.Optional;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
+import org.opendaylight.controller.config.util.capability.BasicCapability;
+import org.opendaylight.controller.config.util.capability.Capability;
+import org.opendaylight.netconf.api.monitoring.NetconfManagementSession;
+import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.netconf.api.monitoring.SessionEvent;
+import org.opendaylight.netconf.notifications.BaseNotificationPublisherRegistration;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.SessionBuilder;
+
+public class NetconfSessionMonitoringServiceTest {
+
+ private static final Session SESSION_1 = new SessionBuilder()
+ .setSessionId(1L)
+ .setSourceHost(new Host("0.0.0.0".toCharArray()))
+ .setUsername("admin")
+ .build();
+ private static final Session SESSION_2 = new SessionBuilder()
+ .setSessionId(2L)
+ .setSourceHost(new Host("0.0.0.0".toCharArray()))
+ .setUsername("admin")
+ .build();
+
+ @Mock
+ private NetconfManagementSession sessionMock1;
+ @Mock
+ private NetconfManagementSession sessionMock2;
+ @Mock
+ private NetconfMonitoringService.SessionsListener listener;
+ @Mock
+ private BaseNotificationPublisherRegistration notificationPublisher;
+
+ private NetconfSessionMonitoringService monitoringService;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ doReturn(SESSION_1).when(sessionMock1).toManagementSession();
+ doReturn(SESSION_2).when(sessionMock2).toManagementSession();
+ doNothing().when(listener).onSessionStarted(any());
+ doNothing().when(listener).onSessionEnded(any());
+
+ doNothing().when(notificationPublisher).onCapabilityChanged(any());
+ doNothing().when(notificationPublisher).onSessionStarted(any());
+ doNothing().when(notificationPublisher).onSessionEnded(any());
+
+ monitoringService = new NetconfSessionMonitoringService(Optional.absent(), 0);
+ monitoringService.registerListener(listener);
+ }
+
+ @Test
+ public void testListeners() throws Exception {
+ monitoringService.onSessionUp(sessionMock1);
+ HashSet<Capability> added = new HashSet<>();
+ added.add(new BasicCapability("toAdd"));
+ monitoringService.onSessionDown(sessionMock1);
+ verify(listener).onSessionStarted(any());
+ verify(listener).onSessionEnded(any());
+ }
+
+
+ @Test
+ public void testClose() throws Exception {
+ monitoringService.onSessionUp(sessionMock1);
+ Assert.assertFalse(monitoringService.getSessions().getSession().isEmpty());
+ monitoringService.close();
+ Assert.assertTrue(monitoringService.getSessions().getSession().isEmpty());
+ }
+
+
+ @Test
+ public void testOnSessionUpAndDown() throws Exception {
+ monitoringService.onSessionUp(sessionMock1);
+ ArgumentCaptor<Session> sessionUpCaptor = ArgumentCaptor.forClass(Session.class);
+ verify(listener).onSessionStarted(sessionUpCaptor.capture());
+ final Session sesionUp = sessionUpCaptor.getValue();
+ Assert.assertEquals(SESSION_1.getSessionId(), sesionUp.getSessionId());
+ Assert.assertEquals(SESSION_1.getSourceHost(), sesionUp.getSourceHost());
+ Assert.assertEquals(SESSION_1.getUsername(), sesionUp.getUsername());
+
+ monitoringService.onSessionDown(sessionMock1);
+ ArgumentCaptor<Session> sessionDownCaptor = ArgumentCaptor.forClass(Session.class);
+ verify(listener).onSessionEnded(sessionDownCaptor.capture());
+ final Session sessionDown = sessionDownCaptor.getValue();
+ Assert.assertEquals(SESSION_1.getSessionId(), sessionDown.getSessionId());
+ Assert.assertEquals(SESSION_1.getSourceHost(), sessionDown.getSourceHost());
+ Assert.assertEquals(SESSION_1.getUsername(), sessionDown.getUsername());
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testListenerUpdateSession() throws Exception {
+ ScheduledThreadPool threadPool = mock(ScheduledThreadPool.class);
+ ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
+ doReturn(executor).when(threadPool).getExecutor();
+ monitoringService = new NetconfSessionMonitoringService(Optional.of(threadPool), 1);
+ monitoringService.registerListener(listener);
+ monitoringService.onSessionUp(sessionMock1);
+ monitoringService.onSessionUp(sessionMock2);
+ monitoringService.onSessionEvent(SessionEvent.inRpcSuccess(sessionMock1));
+ ArgumentCaptor<Collection> captor =
+ ArgumentCaptor.forClass(Collection.class);
+ verify(listener, timeout(2000)).onSessionsUpdated(captor.capture());
+ final Collection<Session> value = captor.getValue();
+ Assert.assertTrue(value.contains(SESSION_1));
+ Assert.assertFalse(value.contains(SESSION_2));
+ monitoringService.close();
+ }
+}
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">dom:netconf-northbound-mapper</type>
<name>mapper-aggregator</name>
</aggregator>
+ <scheduled-threadpool xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool">prefix:threadpool</type>
+ <name>global-netconf-ssh-scheduled-executor</name>
+ </scheduled-threadpool>
+ <monitoring-update-interval xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">6</monitoring-update-interval>
</module>
<module>
import org.mockito.MockitoAnnotations;
import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.netconf.api.monitoring.SessionListener;
import org.opendaylight.netconf.monitoring.xml.model.NetconfState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
final NetconfState model = new NetconfState(monitoringService);
final String xml = XmlUtil.toString(new JaxBSerializer().toXml(model)).replaceAll("\\s", "");
- System.out.println(xml);
assertThat(xml, CoreMatchers.containsString(
"<schema>" +
"<format>yang</format>" +
import java.util.Set;
import javax.annotation.Nullable;
import org.opendaylight.controller.config.util.capability.Capability;
-import org.opendaylight.netconf.api.monitoring.NetconfManagementSession;
import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.netconf.api.monitoring.SessionListener;
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.Yang;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities;
return EMPTY_SESSIONS;
}
+ @Override
+ public SessionListener getSessionListener() {
+ return null;
+ }
+
@Override
public Schemas getSchemas() {
return schemas;
}
@Override
- public AutoCloseable registerListener(MonitoringListener listener) {
+ public AutoCloseable registerCapabilitiesListener(CapabilitiesListener listener) {
return null;
}
@Override
- public void onSessionUp(NetconfManagementSession session) {
-
- }
-
- @Override
- public void onSessionDown(NetconfManagementSession session) {
-
+ public AutoCloseable registerSessionsListener(SessionsListener listener) {
+ return null;
}
- @Override
- public void onCapabilitiesChanged(Set<Capability> added, Set<Capability> removed) {
-
- }
}