Fixes race condition that was observed in ITs, where config pusher started pushing
empty configuration and immediately registered itself as notification listener of
a JMX bean that was not yet present. Fix waits both for netconf-impl and
config-netconf-connector services so that both dependencies are activated before
pushing of configuration can occur.
Change-Id: Id328dc3bd7e41bad59bb84b03461d89f5faeeea4
Signed-off-by: Tomas Olvecky <tolvecky@cisco.com>
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
@Mock
NetconfOperationRouter netconfOperationRouter;
@Mock
- NetconfOperationServiceSnapshot netconfOperationServiceSnapshot;
+ NetconfOperationServiceSnapshotImpl netconfOperationServiceSnapshot;
private TransactionProvider transactionProvider;
import com.google.common.annotations.VisibleForTesting;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
import org.opendaylight.controller.netconf.persist.impl.ConfigPusher;
import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator;
+import org.opendaylight.controller.netconf.util.CloseableUtil;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
public class ConfigPersisterActivator implements BundleActivator {
private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterActivator.class);
+ private static final MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
public static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY = "maxWaitForCapabilitiesMillis";
private static final long MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT = TimeUnit.MINUTES.toMillis(2);
public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX = "storageAdapterClass";
-
- private static final MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
-
private List<AutoCloseable> autoCloseables;
autoCloseables = new ArrayList<>();
PropertiesProviderBaseImpl propertiesProvider = new PropertiesProviderBaseImpl(context);
-
final PersisterAggregator persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
autoCloseables.add(persisterAggregator);
- final long maxWaitForCapabilitiesMillis = getMaxWaitForCapabilitiesMillis(propertiesProvider);
- final List<ConfigSnapshotHolder> configs = persisterAggregator.loadLastConfigs();
- final long conflictingVersionTimeoutMillis = getConflictingVersionTimeoutMillis(propertiesProvider);
+ long maxWaitForCapabilitiesMillis = getMaxWaitForCapabilitiesMillis(propertiesProvider);
+ List<ConfigSnapshotHolder> configs = persisterAggregator.loadLastConfigs();
+ long conflictingVersionTimeoutMillis = getConflictingVersionTimeoutMillis(propertiesProvider);
logger.trace("Following configs will be pushed: {}", configs);
- ServiceTrackerCustomizer<NetconfOperationServiceFactory, NetconfOperationServiceFactory> configNetconfCustomizer = new ServiceTrackerCustomizer<NetconfOperationServiceFactory, NetconfOperationServiceFactory>() {
- @Override
- public NetconfOperationServiceFactory addingService(ServiceReference<NetconfOperationServiceFactory> reference) {
- NetconfOperationServiceFactory service = reference.getBundle().getBundleContext().getService(reference);
- final ConfigPusher configPusher = new ConfigPusher(service, maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
- logger.debug("Configuration Persister got %s", service);
- final Thread pushingThread = new Thread(new Runnable() {
- @Override
- public void run() {
- configPusher.pushConfigs(configs);
- logger.info("Configuration Persister initialization completed.");
- ConfigPersisterNotificationHandler jmxNotificationHandler = new ConfigPersisterNotificationHandler(platformMBeanServer, persisterAggregator);
- synchronized (ConfigPersisterActivator.this) {
- autoCloseables.add(jmxNotificationHandler);
- }
- }
- }, "config-pusher");
- synchronized (ConfigPersisterActivator.this){
- autoCloseables.add(new AutoCloseable() {
- @Override
- public void close() throws Exception {
- pushingThread.interrupt();
- }
- });
- }
- pushingThread.start();
- return service;
- }
- @Override
- public void modifiedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
- }
+ InnerCustomizer innerCustomizer = new InnerCustomizer(configs, maxWaitForCapabilitiesMillis,
+ conflictingVersionTimeoutMillis, persisterAggregator);
+ OuterCustomizer outerCustomizer = new OuterCustomizer(context, innerCustomizer);
+ new ServiceTracker<>(context, NetconfOperationProvider.class, outerCustomizer).open();
+ }
- @Override
- public void removedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
- }
- };
+ private long getConflictingVersionTimeoutMillis(PropertiesProviderBaseImpl propertiesProvider) {
+ String timeoutProperty = propertiesProvider.getProperty(CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY);
+ return timeoutProperty == null ? CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT : Long.valueOf(timeoutProperty);
+ }
- Filter filter = context.createFilter(getFilterString());
+ private long getMaxWaitForCapabilitiesMillis(PropertiesProviderBaseImpl propertiesProvider) {
+ String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY);
+ return timeoutProperty == null ? MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT : Long.valueOf(timeoutProperty);
+ }
- ServiceTracker<NetconfOperationServiceFactory, NetconfOperationServiceFactory> tracker =
- new ServiceTracker<>(context, filter, configNetconfCustomizer);
- tracker.open();
+ @Override
+ public synchronized void stop(BundleContext context) throws Exception {
+ CloseableUtil.closeAll(autoCloseables);
}
")";
}
- private long getConflictingVersionTimeoutMillis(PropertiesProviderBaseImpl propertiesProvider) {
- String timeoutProperty = propertiesProvider.getProperty(CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY);
- return timeoutProperty == null ? CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT : Long.valueOf(timeoutProperty);
- }
+ class OuterCustomizer implements ServiceTrackerCustomizer<NetconfOperationProvider, NetconfOperationProvider> {
+ private final BundleContext context;
+ private final InnerCustomizer innerCustomizer;
- private long getMaxWaitForCapabilitiesMillis(PropertiesProviderBaseImpl propertiesProvider) {
- String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY);
- return timeoutProperty == null ? MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT : Long.valueOf(timeoutProperty);
- }
+ OuterCustomizer(BundleContext context, InnerCustomizer innerCustomizer) {
+ this.context = context;
+ this.innerCustomizer = innerCustomizer;
+ }
- @Override
- public synchronized void stop(BundleContext context) throws Exception {
- Exception lastException = null;
- for (AutoCloseable autoCloseable : autoCloseables) {
+ @Override
+ public NetconfOperationProvider addingService(ServiceReference<NetconfOperationProvider> reference) {
+ logger.trace("Got OuterCustomizer.addingService {}", reference);
+ // JMX was registered, track config-netconf-connector
+ Filter filter;
try {
- autoCloseable.close();
- } catch (Exception e) {
- if (lastException == null) {
- lastException = e;
- } else {
- lastException.addSuppressed(e);
+ filter = context.createFilter(getFilterString());
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalStateException(e);
+ }
+ new ServiceTracker<>(context, filter, innerCustomizer).open();
+ return null;
+ }
+
+ @Override
+ public void modifiedService(ServiceReference<NetconfOperationProvider> reference, NetconfOperationProvider service) {
+
+ }
+
+ @Override
+ public void removedService(ServiceReference<NetconfOperationProvider> reference, NetconfOperationProvider service) {
+
+ }
+ }
+
+ class InnerCustomizer implements ServiceTrackerCustomizer<NetconfOperationServiceFactory, NetconfOperationServiceFactory> {
+ private final List<ConfigSnapshotHolder> configs;
+ private final PersisterAggregator persisterAggregator;
+ private final long maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis;
+
+
+ InnerCustomizer(List<ConfigSnapshotHolder> configs, long maxWaitForCapabilitiesMillis, long conflictingVersionTimeoutMillis,
+ PersisterAggregator persisterAggregator) {
+ this.configs = configs;
+ this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
+ this.conflictingVersionTimeoutMillis = conflictingVersionTimeoutMillis;
+ this.persisterAggregator = persisterAggregator;
+ }
+
+ @Override
+ public NetconfOperationServiceFactory addingService(ServiceReference<NetconfOperationServiceFactory> reference) {
+ logger.trace("Got InnerCustomizer.addingService {}", reference);
+ NetconfOperationServiceFactory service = reference.getBundle().getBundleContext().getService(reference);
+
+ final ConfigPusher configPusher = new ConfigPusher(service, maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
+ logger.debug("Configuration Persister got {}", service);
+ final Thread pushingThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ configPusher.pushConfigs(configs);
+ logger.info("Configuration Persister initialization completed.");
+ ConfigPersisterNotificationHandler jmxNotificationHandler = new ConfigPersisterNotificationHandler(platformMBeanServer, persisterAggregator);
+ synchronized (ConfigPersisterActivator.this) {
+ autoCloseables.add(jmxNotificationHandler);
+ }
}
+ }, "config-pusher");
+ synchronized (ConfigPersisterActivator.this) {
+ autoCloseables.add(new AutoCloseable() {
+ @Override
+ public void close() throws Exception {
+ pushingThread.interrupt();
+ }
+ });
}
+ pushingThread.start();
+ return service;
+ }
+
+ @Override
+ public void modifiedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
}
- if (lastException != null) {
- throw lastException;
+
+ @Override
+ public void removedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
}
+
}
}
+
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
-import javax.management.MBeanServer;
import java.io.IOException;
-import java.lang.management.ManagementFactory;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
private MockedBundleContext ctx;
private ConfigPersisterActivator configPersisterActivator;
- private static final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
private TestingExceptionHandler handler;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.config.persist.api.Persister;
import org.opendaylight.controller.config.persist.api.PropertiesProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
import org.opendaylight.controller.netconf.persist.impl.DummyAdapter;
@Mock
private BundleContext context;
@Mock
- private Filter filter;
+ private Filter outerFilter, innerFilter;
@Mock
private ServiceReference<?> serviceReference;
@Mock
MockitoAnnotations.initMocks(this);
doReturn(null).when(context).getProperty(anyString());
initContext(maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
- doReturn(filter).when(context).createFilter(ConfigPersisterActivator.getFilterString());
- String filterString = "filter";
- doReturn(filterString).when(filter).toString();
- doNothing().when(context).addServiceListener(any(ServiceListener.class), eq(filterString));
+
+ String outerFilterString = "(objectClass=org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider)";
+ doReturn(outerFilter).when(context).createFilter(outerFilterString);
+ doNothing().when(context).addServiceListener(any(ServiceListener.class), eq(outerFilterString));
ServiceReference<?>[] toBeReturned = {serviceReference};
- doReturn(toBeReturned).when(context).getServiceReferences((String) null, filterString);
+ doReturn(toBeReturned).when(context).getServiceReferences(NetconfOperationProvider.class.getName(), null);
+
+ String innerFilterString = "innerfilter";
+ doReturn(innerFilterString).when(outerFilter).toString();
+
+ doReturn(innerFilter).when(context).createFilter(ConfigPersisterActivator.getFilterString());
+ doReturn(innerFilterString).when(innerFilter).toString();
+ doNothing().when(context).addServiceListener(any(ServiceListener.class), eq(innerFilterString));
+
+ doReturn(toBeReturned).when(context).getServiceReferences((String) null, innerFilterString);
doReturn(bundle).when(serviceReference).getBundle();
doReturn(context).when(bundle).getBundleContext();
doReturn("").when(serviceReference).toString();
doReturn(service).when(serviceFactory).createService(anyString());
doReturn(Collections.emptySet()).when(service).getCapabilities();
doNothing().when(service).close();
+ doReturn("serviceFactoryMock").when(serviceFactory).toString();
}
public BundleContext getBundleContext() {
Document onNetconfMessage(Document message, NetconfSession session)
throws NetconfDocumentedException;
- @Override
- void close();
}
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
import org.opendaylight.controller.netconf.mapping.api.Capability;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
package org.opendaylight.controller.netconf.impl;
-import static com.google.common.base.Preconditions.checkState;
-
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
+import static com.google.common.base.Preconditions.checkState;
public class NetconfServerSessionListener implements NetconfSessionListener<NetconfServerSession> {
public static final String MESSAGE_ID = "message-id";
}
@Override
- public void onSessionDown(NetconfServerSession netconfNetconfServerSession, Exception e) {
- logger.debug("Session {} down, reason: {}", netconfNetconfServerSession, e.getMessage());
+ public void onSessionDown(NetconfServerSession netconfNetconfServerSession, Exception cause) {
+ logger.debug("Session {} down, reason: {}", netconfNetconfServerSession, cause.getMessage());
monitoringService.onSessionDown(netconfNetconfServerSession);
- operationRouter.close();
+ try {
+ operationRouter.close();
+ } catch (Exception closingEx) {
+ logger.debug("Ignoring exception while closing operationRouter", closingEx);
+ }
}
@Override
netconfTerminationReason.getErrorMessage());
monitoringService.onSessionDown(netconfNetconfServerSession);
- operationRouter.close();
+ try {
+ operationRouter.close();
+ } catch (Exception closingEx) {
+ logger.debug("Ignoring exception while closing operationRouter", closingEx);
+ }
}
@Override
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
import org.opendaylight.protocol.framework.SessionListenerFactory;
+import static org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider.NetconfOperationProviderUtil.getNetconfSessionIdForReporting;
+
public class NetconfServerSessionListenerFactory implements SessionListenerFactory<NetconfServerSessionListener> {
- private final NetconfOperationServiceFactoryListener factoriesListener;
+ private final NetconfOperationProvider netconfOperationProvider;
private final DefaultCommitNotificationProducer commitNotifier;
private final SessionMonitoringService monitor;
- public NetconfServerSessionListenerFactory(NetconfOperationServiceFactoryListener factoriesListener,
+ public NetconfServerSessionListenerFactory(NetconfOperationProvider netconfOperationProvider,
DefaultCommitNotificationProducer commitNotifier,
SessionIdProvider idProvider, SessionMonitoringService monitor) {
- this.factoriesListener = factoriesListener;
+ this.netconfOperationProvider = netconfOperationProvider;
this.commitNotifier = commitNotifier;
this.idProvider = idProvider;
this.monitor = monitor;
@Override
public NetconfServerSessionListener getSessionListener() {
- NetconfOperationServiceSnapshot netconfOperationServiceSnapshot = factoriesListener.getSnapshot(idProvider
- .getCurrentSessionId());
+ NetconfOperationServiceSnapshot netconfOperationServiceSnapshot = netconfOperationProvider.getSnapshot(
+ getNetconfSessionIdForReporting(idProvider.getCurrentSessionId()));
CapabilityProvider capabilityProvider = new CapabilityProviderImpl(netconfOperationServiceSnapshot);
import io.netty.util.concurrent.Promise;
import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.util.NetconfUtil;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
import javax.xml.xpath.XPathExpression;
import java.io.InputStream;
+import static org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider.NetconfOperationProviderUtil.getNetconfSessionIdForReporting;
+
public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfHelloMessage, NetconfServerSession, NetconfServerSessionListener> {
public static final String SERVER_HELLO_XML_LOCATION = "/server_hello.xml";
private static final Document helloMessageTemplate = loadHelloMessageTemplate();
private final SessionIdProvider idProvider;
- private final NetconfOperationServiceFactoryListener factoriesListener;
+ private final NetconfOperationProvider netconfOperationProvider;
private final long connectionTimeoutMillis;
- public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationServiceFactoryListener factoriesListener,
+ public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationProvider netconfOperationProvider,
SessionIdProvider idProvider, long connectionTimeoutMillis) {
this.timer = timer;
- this.factoriesListener = factoriesListener;
+ this.netconfOperationProvider = netconfOperationProvider;
this.idProvider = idProvider;
this.connectionTimeoutMillis = connectionTimeoutMillis;
}
final Element capabilitiesElement = (Element) XmlUtil.evaluateXPath(capabilitiesXPath, helloMessageTemplate,
XPathConstants.NODE);
- CapabilityProvider capabilityProvider = new CapabilityProviderImpl(factoriesListener.getSnapshot(sessionId));
+ CapabilityProvider capabilityProvider = new CapabilityProviderImpl(netconfOperationProvider.getSnapshot(
+ getNetconfSessionIdForReporting(sessionId)));
for (String capability : capabilityProvider.getCapabilities()) {
final Element capabilityElement = helloMessageTemplate.createElement(XmlNetconfConstants.CAPABILITY);
package org.opendaylight.controller.netconf.impl.mapping.operations;
-import java.util.Collections;
-
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import java.util.Collections;
+
public class DefaultCloseSession extends AbstractSingletonNetconfOperation {
public static final String CLOSE_SESSION = "close-session";
private final AutoCloseable sessionResources;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
private NetconfOperationServiceFactoryTracker factoriesTracker;
private DefaultCommitNotificationProducer commitNot;
- private NetconfServerDispatcher dispatch;
private NioEventLoopGroup eventLoopGroup;
private HashedWheelTimer timer;
private ServiceRegistration<NetconfMonitoringService> regMonitoring;
NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
serverNegotiatorFactory, listenerFactory);
- dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
+ NetconfServerDispatcher dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
logger.info("Starting TCP netconf server at {}", address);
dispatch.createServer(address);
+ context.registerService(NetconfOperationProvider.class, factoriesListener, null);
+
}
private void startOperationServiceFactoryTracker(BundleContext context, NetconfOperationServiceFactoryListenerImpl factoriesListener) {
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.mapping.api.Capability;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
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.Schemas;
private static final Logger logger = LoggerFactory.getLogger(NetconfMonitoringServiceImpl.class);
private final Set<NetconfManagementSession> sessions = new ConcurrentSet<>();
- private final NetconfOperationServiceFactoryListener factoriesListener;
+ private final NetconfOperationProvider netconfOperationProvider;
- public NetconfMonitoringServiceImpl(NetconfOperationServiceFactoryListener factoriesListener) {
- this.factoriesListener = factoriesListener;
+ public NetconfMonitoringServiceImpl(NetconfOperationProvider netconfOperationProvider) {
+ this.netconfOperationProvider = netconfOperationProvider;
}
@Override
@Override
public void onSessionDown(NetconfManagementSession session) {
logger.debug("Session {} down", session);
- Preconditions.checkState(sessions.contains(session) == true, "Session %s not present", session);
+ Preconditions.checkState(sessions.contains(session), "Session %s not present", session);
sessions.remove(session);
}
@Override
public Schemas getSchemas() {
- // FIXME, session ID
// capabilities should be split from operations (it will allow to move getSchema operation to monitoring module)
- return transformSchemas(factoriesListener.getSnapshot(0));
+ try (NetconfOperationServiceSnapshot snapshot = netconfOperationProvider.getSnapshot("netconf-monitoring")) {
+ return transformSchemas(snapshot.getServices());
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IllegalStateException("Exception while closing", e);
+ }
}
- private Schemas transformSchemas(NetconfOperationServiceSnapshot snapshot) {
+ private Schemas transformSchemas(Set<NetconfOperationService> services) {
Set<Capability> caps = Sets.newHashSet();
List<Schema> schemas = Lists.newArrayList();
- for (NetconfOperationService netconfOperationService : snapshot.getServices()) {
+
+ for (NetconfOperationService netconfOperationService : services) {
// TODO check for duplicates ? move capability merging to snapshot
// Split capabilities from operations first and delete this duplicate code
caps.addAll(netconfOperationService.getCapabilities());
for (Capability cap : caps) {
SchemaBuilder builder = new SchemaBuilder();
- if(cap.getCapabilitySchema().isPresent() == false)
+ if (cap.getCapabilitySchema().isPresent() == false) {
continue;
+ }
Preconditions.checkState(cap.getModuleNamespace().isPresent());
builder.setNamespace(new Uri(cap.getModuleNamespace().get()));
builder.setFormat(Yang.class);
- builder.setLocation(transformLocations(cap.getLocation().or(Collections.<String> emptyList())));
+ builder.setLocation(transformLocations(cap.getLocation().or(Collections.<String>emptyList())));
builder.setKey(new SchemaKey(Yang.class, identifier, version));
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
String errorMessage = String.format("Unable to handle rpc %s on session %s", messageAsString, session);
Map<String, String> errorInfo = Maps.newHashMap();
- NetconfDocumentedException.ErrorTag tag = null;
+ NetconfDocumentedException.ErrorTag tag;
if (e instanceof IllegalArgumentException) {
errorInfo.put(NetconfDocumentedException.ErrorTag.operation_not_supported.toString(), e.getMessage());
tag = NetconfDocumentedException.ErrorTag.operation_not_supported;
- } else if (e instanceof IllegalStateException) {
+ } else {
errorInfo.put(NetconfDocumentedException.ErrorTag.operation_failed.toString(), e.getMessage());
tag = NetconfDocumentedException.ErrorTag.operation_failed;
}
}
@Override
- public void close() {
+ public void close() throws Exception {
netconfOperationServiceSnapshot.close();
}
void onRemoveNetconfOperationServiceFactory(NetconfOperationServiceFactory service);
- NetconfOperationServiceSnapshot getSnapshot(long sessionId);
+
}
*/
package org.opendaylight.controller.netconf.impl.osgi;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+
import java.util.HashSet;
import java.util.Set;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-
-public class NetconfOperationServiceFactoryListenerImpl implements NetconfOperationServiceFactoryListener {
+public class NetconfOperationServiceFactoryListenerImpl implements NetconfOperationServiceFactoryListener,
+ NetconfOperationProvider {
private final Set<NetconfOperationServiceFactory> allFactories = new HashSet<>();
@Override
}
@Override
- public synchronized NetconfOperationServiceSnapshot getSnapshot(long sessionId) {
- return new NetconfOperationServiceSnapshot(allFactories, sessionId);
+ public synchronized NetconfOperationServiceSnapshotImpl getSnapshot(String sessionIdForReporting) {
+ return new NetconfOperationServiceSnapshotImpl(allFactories, sessionIdForReporting);
}
}
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.util.CloseableUtil;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-public class NetconfOperationServiceSnapshot implements AutoCloseable {
- private static final Logger logger = LoggerFactory.getLogger(NetconfOperationServiceSnapshot.class);
+public class NetconfOperationServiceSnapshotImpl implements NetconfOperationServiceSnapshot {
private final Set<NetconfOperationService> services;
private final String netconfSessionIdForReporting;
- public NetconfOperationServiceSnapshot(Set<NetconfOperationServiceFactory> factories, long sessionId) {
+ public NetconfOperationServiceSnapshotImpl(Set<NetconfOperationServiceFactory> factories, String sessionIdForReporting) {
Set<NetconfOperationService> services = new HashSet<>();
- netconfSessionIdForReporting = getNetconfSessionIdForReporting(sessionId);
+ netconfSessionIdForReporting = sessionIdForReporting;
for (NetconfOperationServiceFactory factory : factories) {
services.add(factory.createService(netconfSessionIdForReporting));
}
this.services = Collections.unmodifiableSet(services);
}
- private static String getNetconfSessionIdForReporting(long sessionId) {
- return "netconf session id " + sessionId;
- }
+
+ @Override
public String getNetconfSessionIdForReporting() {
return netconfSessionIdForReporting;
}
+ @Override
public Set<NetconfOperationService> getServices() {
return services;
}
@Override
- public void close() {
- RuntimeException firstException = null;
- for (NetconfOperationService service : services) {
- try {
- service.close();
- } catch (RuntimeException e) {
- logger.warn("Got exception while closing {}", service, e);
- if (firstException == null) {
- firstException = e;
- } else {
- firstException.addSuppressed(e);
- }
- }
- }
- if (firstException != null) {
- throw firstException;
- }
+ public void close() throws Exception {
+ CloseableUtil.closeAll(services);
}
@Override
public String toString() {
- return "NetconfOperationServiceSnapshot{" + netconfSessionIdForReporting + '}';
+ return "NetconfOperationServiceSnapshotImpl{" + netconfSessionIdForReporting + '}';
}
}
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
import java.lang.management.ManagementFactory;
commitNot = new DefaultCommitNotificationProducer(
ManagementFactory.getPlatformMBeanServer());
- NetconfOperationServiceFactoryListener factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+ NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
SessionIdProvider idProvider = new SessionIdProvider();
hashedWheelTimer = new HashedWheelTimer();
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
import org.opendaylight.controller.netconf.mapping.api.Capability;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(NetconfITTest.getModuleFactoriesS().toArray(
new ModuleFactory[0])));
- NetconfMonitoringServiceImpl monitoringService = new NetconfMonitoringServiceImpl(getFactoriesListener());
+ NetconfMonitoringServiceImpl monitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
}
- public NetconfOperationServiceFactoryListener getFactoriesListener() {
- NetconfOperationServiceFactoryListener factoriesListener = mock(NetconfOperationServiceFactoryListener.class);
- NetconfOperationServiceSnapshot snap = mock(NetconfOperationServiceSnapshot.class);
+ public NetconfOperationProvider getNetconfOperationProvider() {
+ NetconfOperationProvider factoriesListener = mock(NetconfOperationProvider.class);
+ NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
NetconfOperationService service = mock(NetconfOperationService.class);
Set<Capability> caps = Sets.newHashSet();
doReturn(caps).when(service).getCapabilities();
Set<NetconfOperationService> services = Sets.newHashSet(service);
doReturn(services).when(snap).getServices();
- doReturn(snap).when(factoriesListener).getSnapshot(anyLong());
+ doReturn(snap).when(factoriesListener).getSnapshot(anyString());
return factoriesListener;
}
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
-import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
}
static NetconfMonitoringServiceImpl getNetconfMonitoringListenerService() {
- NetconfOperationServiceFactoryListener factoriesListener = mock(NetconfOperationServiceFactoryListener.class);
- NetconfOperationServiceSnapshot snap = mock(NetconfOperationServiceSnapshot.class);
+ NetconfOperationProvider netconfOperationProvider = mock(NetconfOperationProvider.class);
+ NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
doReturn(Collections.<NetconfOperationService>emptySet()).when(snap).getServices();
- doReturn(snap).when(factoriesListener).getSnapshot(anyLong());
- return new NetconfMonitoringServiceImpl(factoriesListener);
+ doReturn(snap).when(netconfOperationProvider).getSnapshot(anyString());
+ return new NetconfMonitoringServiceImpl(netconfOperationProvider);
}
@After
*/
package org.opendaylight.controller.netconf.it;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
import io.netty.channel.ChannelFuture;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
import junit.framework.Assert;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.matchers.JUnitMatchers;
import org.mockito.Mock;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.spi.ModuleFactory;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
import org.opendaylight.controller.netconf.mapping.api.Capability;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator;
import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
public class NetconfMonitoringITTest extends AbstractNetconfConfigTest {
super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(NetconfITTest.getModuleFactoriesS().toArray(
new ModuleFactory[0])));
- monitoringService = new NetconfMonitoringServiceImpl(getFactoriesListener());
+ monitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
private void assertSessionElementsInResponse(Document document, int i) {
int elementSize = document.getElementsByTagName("session-id").getLength();
- Assert.assertEquals(i, elementSize);
+ Assert.assertEquals("Incorrect number of session-id tags in " + XmlUtil.toString(document),i, elementSize);
}
private NetconfMessage loadGetMessage() throws Exception {
return XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/get.xml");
}
- public static NetconfOperationServiceFactoryListener getFactoriesListener() {
- NetconfOperationServiceFactoryListener factoriesListener = mock(NetconfOperationServiceFactoryListener.class);
- NetconfOperationServiceSnapshot snap = mock(NetconfOperationServiceSnapshot.class);
+ public static NetconfOperationProvider getNetconfOperationProvider() throws Exception {
+ NetconfOperationProvider factoriesListener = mock(NetconfOperationProvider.class);
+ NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
+ doNothing().when(snap).close();
NetconfOperationService service = mock(NetconfOperationService.class);
Set<Capability> caps = Sets.newHashSet();
caps.add(new Capability() {
doReturn(caps).when(service).getCapabilities();
Set<NetconfOperationService> services = Sets.newHashSet(service);
doReturn(services).when(snap).getServices();
- doReturn(snap).when(factoriesListener).getSnapshot(anyLong());
+ doReturn(snap).when(factoriesListener).getSnapshot(anyString());
return factoriesListener;
}
--- /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.controller.netconf.mapping.api;
+
+public interface NetconfOperationProvider {
+
+ NetconfOperationServiceSnapshot getSnapshot(String sessionIdForReporting);
+
+ public static class NetconfOperationProviderUtil {
+
+ public static String getNetconfSessionIdForReporting(long sessionId) {
+ return "netconf session id " + sessionId;
+ }
+
+ }
+
+}
--- /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.controller.netconf.mapping.api;
+
+import java.util.Set;
+
+public interface NetconfOperationServiceSnapshot extends AutoCloseable {
+ String getNetconfSessionIdForReporting();
+
+ Set<NetconfOperationService> getServices();
+
+}
--- /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.controller.netconf.util;
+
+public class CloseableUtil {
+
+ public static void closeAll(Iterable<? extends AutoCloseable> autoCloseables) throws Exception {
+ Exception lastException = null;
+ for (AutoCloseable autoCloseable : autoCloseables) {
+ try {
+ autoCloseable.close();
+ } catch (Exception e) {
+ if (lastException == null) {
+ lastException = e;
+ } else {
+ lastException.addSuppressed(e);
+ }
+ }
+ }
+ if (lastException != null) {
+ throw lastException;
+ }
+
+ }
+}