Netconf server does not preserve snapshots of schema contexts for each netconf session anymore
Every netconf session is using current SchemaContext
+ Use notification manager to notify about capability changes
Change-Id: Ie47125e1eb6851b54b09d5e4afe38fee323850de
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-monitoring</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-notifications-api</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
<groupId>org.opendaylight.yangtools.thirdparty</groupId>
<artifactId>antlr4-runtime-osgi-nohead</artifactId>
</dependency>
+
<!--Compile scopes for all testing dependencies are intentional-->
<!--This way, all testing dependencies can be transitively used by other integration test modules-->
<!--If the dependencies are test scoped, they are not visible to other maven modules depending on sal-binding-it-->
mavenBundle("org.eclipse.birt.runtime.3_7_1", "org.apache.xml.resolver", "1.2.0"),
mavenBundle(CONTROLLER, "config-netconf-connector").versionAsInProject(), //
+ mavenBundle(CONTROLLER, "netconf-notifications-api").versionAsInProject(), //
+ mavenBundle(CONTROLLER, "ietf-netconf").versionAsInProject(), //
+ mavenBundle(CONTROLLER, "ietf-netconf-notifications").versionAsInProject(), //
mavenBundle(CONTROLLER, "netconf-impl").versionAsInProject(), //
mavenBundle(CONTROLLER, "config-persister-file-xml-adapter").versionAsInProject().noStart(),
<groupId>${project.groupId}</groupId>
<artifactId>netconf-mapping-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-notifications-api</artifactId>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-util</artifactId>
org.opendaylight.controller.netconf.confignetconfconnector.util,
org.opendaylight.controller.netconf.confignetconfconnector.osgi,
org.opendaylight.controller.netconf.confignetconfconnector.exception,</Private-Package>
- <Import-Package>*</Import-Package>
- <Export-Package></Export-Package>
</instructions>
</configuration>
</plugin>
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
private static final Logger LOG = LoggerFactory.getLogger(EditConfig.class);
- private final YangStoreSnapshot yangStoreSnapshot;
+ private final YangStoreContext yangStoreSnapshot;
private final TransactionProvider transactionProvider;
private EditConfigXmlParser editConfigXmlParser;
- public EditConfig(YangStoreSnapshot yangStoreSnapshot, TransactionProvider transactionProvider,
+ public EditConfig(YangStoreContext yangStoreSnapshot, TransactionProvider transactionProvider,
ConfigRegistryClient configRegistryClient, String netconfSessionIdForReporting) {
super(configRegistryClient, netconfSessionIdForReporting);
this.yangStoreSnapshot = yangStoreSnapshot;
}
}
- public static Config getConfigMapping(ConfigRegistryClient configRegistryClient, YangStoreSnapshot yangStoreSnapshot) {
+ public static Config getConfigMapping(ConfigRegistryClient configRegistryClient, YangStoreContext yangStoreSnapshot) {
Map<String, Map<String, ModuleConfig>> factories = transformMbeToModuleConfigs(configRegistryClient,
yangStoreSnapshot.getModuleMXBeanEntryMap());
Map<String, Map<Date, IdentityMapping>> identitiesMap = transformIdentities(yangStoreSnapshot.getModules());
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException;
import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
public class Get extends AbstractConfigNetconfOperation {
- private final YangStoreSnapshot yangStoreSnapshot;
+ private final YangStoreContext yangStoreSnapshot;
private static final Logger LOG = LoggerFactory.getLogger(Get.class);
- public Get(YangStoreSnapshot yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
+ public Get(YangStoreContext yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
String netconfSessionIdForReporting) {
super(configRegistryClient, netconfSessionIdForReporting);
this.yangStoreSnapshot = yangStoreSnapshot;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException;
public static final String GET_CONFIG = "get-config";
- private final YangStoreSnapshot yangStoreSnapshot;
+ private final YangStoreContext yangStoreSnapshot;
private final Optional<String> maybeNamespace;
private final TransactionProvider transactionProvider;
private static final Logger LOG = LoggerFactory.getLogger(GetConfig.class);
- public GetConfig(YangStoreSnapshot yangStoreSnapshot, Optional<String> maybeNamespace,
+ public GetConfig(YangStoreContext yangStoreSnapshot, Optional<String> maybeNamespace,
TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient,
String netconfSessionIdForReporting) {
super(configRegistryClient, netconfSessionIdForReporting);
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.ModuleRpcs;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.Rpcs;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
private static final Logger LOG = LoggerFactory.getLogger(RuntimeRpc.class);
public static final String CONTEXT_INSTANCE = "context-instance";
- private final YangStoreSnapshot yangStoreSnapshot;
+ private final YangStoreContext yangStoreSnapshot;
- public RuntimeRpc(final YangStoreSnapshot yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
+ public RuntimeRpc(final YangStoreContext yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
String netconfSessionIdForReporting) {
super(configRegistryClient, netconfSessionIdForReporting);
this.yangStoreSnapshot = yangStoreSnapshot;
SchemaContextProvider schemaContextProvider = reference.getBundle().getBundleContext().getService(reference);
- YangStoreServiceImpl yangStoreService = new YangStoreServiceImpl(schemaContextProvider);
+ YangStoreService yangStoreService = new YangStoreService(schemaContextProvider, context);
configRegistryLookup = new ConfigRegistryLookupThread(yangStoreService);
configRegistryLookup.start();
return configRegistryLookup;
}
private class ConfigRegistryLookupThread extends Thread {
- private final YangStoreServiceImpl yangStoreService;
+ private final YangStoreService yangStoreService;
- private ConfigRegistryLookupThread(YangStoreServiceImpl yangStoreService) {
+ private ConfigRegistryLookupThread(YangStoreService yangStoreService) {
super("config-registry-lookup");
this.yangStoreService = yangStoreService;
}
final class NetconfOperationProvider {
private final Set<NetconfOperation> operations;
- NetconfOperationProvider(YangStoreSnapshot yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
+ NetconfOperationProvider(YangStoreContext yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
TransactionProvider transactionProvider, String netconfSessionIdForReporting) {
operations = setUpOperations(yangStoreSnapshot, configRegistryClient, transactionProvider,
return operations;
}
- private static Set<NetconfOperation> setUpOperations(YangStoreSnapshot yangStoreSnapshot,
+ private static Set<NetconfOperation> setUpOperations(YangStoreContext yangStoreSnapshot,
ConfigRegistryClient configRegistryClient, TransactionProvider transactionProvider,
String netconfSessionIdForReporting) {
Set<NetconfOperation> ops = Sets.newHashSet();
@Override
public NetconfOperationServiceImpl createService(String netconfSessionIdForReporting) {
- try {
- return new NetconfOperationServiceImpl(yangStoreService, jmxClient, netconfSessionIdForReporting);
- } catch (YangStoreException e) {
- throw new IllegalStateException(e);
- }
+ return new NetconfOperationServiceImpl(yangStoreService, jmxClient, netconfSessionIdForReporting);
}
}
package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
-import org.opendaylight.controller.config.api.LookupRegistry;
import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
import org.opendaylight.controller.netconf.mapping.api.Capability;
import org.opendaylight.yangtools.yang.model.api.Module;
/**
- * Manages life cycle of {@link YangStoreSnapshot}.
+ * Manages life cycle of {@link YangStoreContext}.
*/
public class NetconfOperationServiceImpl implements NetconfOperationService {
- private final YangStoreSnapshot yangStoreSnapshot;
private final NetconfOperationProvider operationProvider;
- private final Set<Capability> capabilities;
private final TransactionProvider transactionProvider;
+ private final YangStoreService yangStoreService;
public NetconfOperationServiceImpl(final YangStoreService yangStoreService, final ConfigRegistryJMXClient jmxClient,
- final String netconfSessionIdForReporting) throws YangStoreException {
+ final String netconfSessionIdForReporting) {
- yangStoreSnapshot = yangStoreService.getYangStoreSnapshot();
- checkConsistencyBetweenYangStoreAndConfig(jmxClient, yangStoreSnapshot);
+ this.yangStoreService = yangStoreService;
transactionProvider = new TransactionProvider(jmxClient, netconfSessionIdForReporting);
- operationProvider = new NetconfOperationProvider(yangStoreSnapshot, jmxClient, transactionProvider,
+ operationProvider = new NetconfOperationProvider(yangStoreService, jmxClient, transactionProvider,
netconfSessionIdForReporting);
- capabilities = setupCapabilities(yangStoreSnapshot);
- }
-
-
- @VisibleForTesting
- static void checkConsistencyBetweenYangStoreAndConfig(final LookupRegistry jmxClient, final YangStoreSnapshot yangStoreSnapshot) {
- Set<String> missingModulesFromConfig = Sets.newHashSet();
-
- Set<String> modulesSeenByConfig = jmxClient.getAvailableModuleFactoryQNames();
- Map<String, Map<String, ModuleMXBeanEntry>> moduleMXBeanEntryMap = yangStoreSnapshot.getModuleMXBeanEntryMap();
-
- for (Map<String, ModuleMXBeanEntry> moduleNameToMBE : moduleMXBeanEntryMap.values()) {
- for (ModuleMXBeanEntry moduleMXBeanEntry : moduleNameToMBE.values()) {
- String moduleSeenByYangStore = moduleMXBeanEntry.getYangModuleQName().toString();
- if(!modulesSeenByConfig.contains(moduleSeenByYangStore)){
- missingModulesFromConfig.add(moduleSeenByYangStore);
- }
- }
- }
-
- Preconditions
- .checkState(
- missingModulesFromConfig.isEmpty(),
- "There are inconsistencies between configuration subsystem and yangstore in terms of discovered yang modules, yang modules missing from config subsystem but present in yangstore: %s, %sAll modules present in config: %s",
- missingModulesFromConfig, System.lineSeparator(), modulesSeenByConfig);
-
}
@Override
public void close() {
- yangStoreSnapshot.close();
transactionProvider.close();
}
@Override
public Set<Capability> getCapabilities() {
- return capabilities;
+ return setupCapabilities(yangStoreService);
}
@Override
return operationProvider.getOperations();
}
- private static Set<Capability> setupCapabilities(final YangStoreSnapshot yangStoreSnapshot) {
+ private static Set<Capability> setupCapabilities(final YangStoreContext yangStoreSnapshot) {
Set<Capability> capabilities = new HashSet<>();
// [RFC6241] 8.3. Candidate Configuration Capability
capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
--- /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.confignetconfconnector.osgi;
+
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+
+public interface YangStoreContext {
+
+ /**
+ * @deprecated Use {@link #getQNamesToIdentitiesToModuleMXBeanEntries()} instead. This method return only one
+ * module representation even if multiple revisions are available.
+ */
+ @Deprecated
+ Map<String/* Namespace from yang file */,
+ Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> getModuleMXBeanEntryMap();
+
+
+ Map<QName, Map<String /* identity local name */, ModuleMXBeanEntry>> getQNamesToIdentitiesToModuleMXBeanEntries();
+
+ /**
+ * Get all modules discovered when this snapshot was created.
+ * @return all modules discovered. If one module exists with two different revisions, return both.
+ */
+ Set<Module> getModules();
+
+ String getModuleSource(ModuleIdentifier moduleIdentifier);
+
+}
+++ /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.confignetconfconnector.osgi;
-
-public class YangStoreException extends Exception {
-
- private static final long serialVersionUID = 2841238836278528836L;
-
- public YangStoreException(String message, Throwable cause) {
- super(message, cause);
- }
-
-}
* 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.confignetconfconnector.osgi;
-/**
- * Yang store OSGi service
- */
-public interface YangStoreService {
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import java.lang.ref.SoftReference;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicReference;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.controller.netconf.notifications.BaseNetconfNotificationListener;
+import org.opendaylight.controller.netconf.notifications.BaseNotificationPublisherRegistration;
+import org.opendaylight.controller.netconf.notifications.NetconfNotificationCollector;
+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.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.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class YangStoreService implements YangStoreContext {
+
+ private static final Logger LOG = LoggerFactory.getLogger(YangStoreService.class);
/**
- * Module entry objects mapped to module names and namespaces.
+ * This is a rather interesting locking model. We need to guard against both the
+ * cache expiring from GC and being invalidated by schema context change. The
+ * context can change while we are doing processing, so we do not want to block
+ * it, so no synchronization can happen on the methods.
+ *
+ * So what we are doing is the following:
*
- * @return actual view of what is available in OSGi service registry.
+ * We synchronize with GC as usual, using a SoftReference.
+ *
+ * The atomic reference is used to synchronize with {@link #refresh()}, e.g. when
+ * refresh happens, it will push a SoftReference(null), e.g. simulate the GC. Now
+ * that may happen while the getter is already busy acting on the old schema context,
+ * so it needs to understand that a refresh has happened and retry. To do that, it
+ * attempts a CAS operation -- if it fails, in knows that the SoftReference has
+ * been replaced and thus it needs to retry.
+ *
+ * Note that {@link #getYangStoreSnapshot()} will still use synchronize() internally
+ * to stop multiple threads doing the same work.
*/
- YangStoreSnapshot getYangStoreSnapshot() throws YangStoreException;
+ private final AtomicReference<SoftReference<YangStoreSnapshot>> ref =
+ new AtomicReference<>(new SoftReference<YangStoreSnapshot>(null));
+
+ private final SchemaContextProvider schemaContextProvider;
+ private final BaseNetconfNotificationListener notificationPublisher;
+
+ private final ExecutorService notificationExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
+ @Override
+ public Thread newThread(final Runnable r) {
+ return new Thread(r, "config-netconf-connector-capability-notifications");
+ }
+ });
+
+ public YangStoreService(final SchemaContextProvider schemaContextProvider, final BundleContext context) {
+ this(schemaContextProvider, new NotificationCollectorTracker(context));
+ }
+
+ public YangStoreService(final SchemaContextProvider schemaContextProvider, final BaseNetconfNotificationListener notificationHandler) {
+ this.schemaContextProvider = schemaContextProvider;
+ this.notificationPublisher = notificationHandler;
+ }
+
+ private synchronized YangStoreContext getYangStoreSnapshot() {
+ SoftReference<YangStoreSnapshot> r = ref.get();
+ YangStoreSnapshot ret = r.get();
+
+ while (ret == null) {
+ // We need to be compute a new value
+ ret = new YangStoreSnapshot(schemaContextProvider.getSchemaContext());
+
+ if (!ref.compareAndSet(r, new SoftReference<>(ret))) {
+ LOG.debug("Concurrent refresh detected, recomputing snapshot");
+ r = ref.get();
+ ret = null;
+ }
+ }
+
+ return ret;
+ }
+
+ @Override
+ public Map<String, Map<String, ModuleMXBeanEntry>> getModuleMXBeanEntryMap() {
+ return getYangStoreSnapshot().getModuleMXBeanEntryMap();
+ }
+
+ @Override
+ public Map<QName, Map<String, ModuleMXBeanEntry>> getQNamesToIdentitiesToModuleMXBeanEntries() {
+ return getYangStoreSnapshot().getQNamesToIdentitiesToModuleMXBeanEntries();
+ }
+
+ @Override
+ public Set<Module> getModules() {
+ return getYangStoreSnapshot().getModules();
+ }
+
+ @Override
+ public String getModuleSource(final ModuleIdentifier moduleIdentifier) {
+ return getYangStoreSnapshot().getModuleSource(moduleIdentifier);
+ }
+
+ public void refresh() {
+ final YangStoreSnapshot previous = ref.get().get();
+ ref.set(new SoftReference<YangStoreSnapshot>(null));
+ notificationExecutor.submit(new CapabilityChangeNotifier(previous));
+ }
+
+ private final class CapabilityChangeNotifier implements Runnable {
+ private final YangStoreSnapshot previous;
+
+ public CapabilityChangeNotifier(final YangStoreSnapshot previous) {
+ this.previous = previous;
+ }
+
+ @Override
+ public void run() {
+ final YangStoreContext current = getYangStoreSnapshot();
+
+ if(current.equals(previous) == false) {
+ notificationPublisher.onCapabilityChanged(computeDiff(previous, current));
+ }
+ }
+ }
+
+ private static final Function<Module, Uri> MODULE_TO_URI = new Function<Module, Uri>() {
+ @Override
+ public Uri apply(final Module input) {
+ final QName qName = QName.cachedReference(QName.create(input.getQNameModule(), input.getName()));
+ return new Uri(qName.toString());
+ }
+ };
+
+ static NetconfCapabilityChange computeDiff(final YangStoreContext previous, final YangStoreContext current) {
+ final Sets.SetView<Module> removed = Sets.difference(previous.getModules(), current.getModules());
+ final Sets.SetView<Module> added = Sets.difference(current.getModules(), previous.getModules());
+
+ final NetconfCapabilityChangeBuilder netconfCapabilityChangeBuilder = new NetconfCapabilityChangeBuilder();
+ netconfCapabilityChangeBuilder.setChangedBy(new ChangedByBuilder().setServerOrUser(new ServerBuilder().setServer(true).build()).build());
+ netconfCapabilityChangeBuilder.setDeletedCapability(Lists.newArrayList(Collections2.transform(removed, MODULE_TO_URI)));
+ netconfCapabilityChangeBuilder.setAddedCapability(Lists.newArrayList(Collections2.transform(added, MODULE_TO_URI)));
+ // TODO modified should be computed ... but why ?
+ netconfCapabilityChangeBuilder.setModifiedCapability(Collections.<Uri>emptyList());
+ return netconfCapabilityChangeBuilder.build();
+ }
+
+
+ /**
+ * Looks for NetconfNotificationCollector service and publishes base netconf notifications if possible
+ */
+ private static class NotificationCollectorTracker implements ServiceTrackerCustomizer<NetconfNotificationCollector, NetconfNotificationCollector>, BaseNetconfNotificationListener, AutoCloseable {
+
+ private final BundleContext context;
+ private final ServiceTracker<NetconfNotificationCollector, NetconfNotificationCollector> listenerTracker;
+ private BaseNotificationPublisherRegistration publisherReg;
+
+ public NotificationCollectorTracker(final BundleContext context) {
+ this.context = context;
+ listenerTracker = new ServiceTracker<>(context, NetconfNotificationCollector.class, this);
+ listenerTracker.open();
+ }
+
+ @Override
+ public synchronized NetconfNotificationCollector addingService(final ServiceReference<NetconfNotificationCollector> reference) {
+ closePublisherRegistration();
+ publisherReg = context.getService(reference).registerBaseNotificationPublisher();
+ return null;
+ }
+
+ @Override
+ public synchronized void modifiedService(final ServiceReference<NetconfNotificationCollector> reference, final NetconfNotificationCollector service) {
+ closePublisherRegistration();
+ publisherReg = context.getService(reference).registerBaseNotificationPublisher();
+ }
+
+ @Override
+ public synchronized void removedService(final ServiceReference<NetconfNotificationCollector> reference, final NetconfNotificationCollector service) {
+ closePublisherRegistration();
+ publisherReg = null;
+ }
+
+ private void closePublisherRegistration() {
+ if(publisherReg != null) {
+ publisherReg.close();
+ }
+ }
+
+ @Override
+ public synchronized void close() {
+ closePublisherRegistration();
+ listenerTracker.close();
+ }
+
+ @Override
+ public void onCapabilityChanged(final NetconfCapabilityChange capabilityChange) {
+ if(publisherReg == null) {
+ LOG.warn("Omitting notification due to missing notification service: {}", capabilityChange);
+ return;
+ }
+ publisherReg.onCapabilityChanged(capabilityChange);
+ }
+ }
}
+++ /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.confignetconfconnector.osgi;
-
-import java.lang.ref.SoftReference;
-import java.util.concurrent.atomic.AtomicReference;
-import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class YangStoreServiceImpl implements YangStoreService {
- private static final Logger LOG = LoggerFactory.getLogger(YangStoreServiceImpl.class);
-
- /**
- * This is a rather interesting locking model. We need to guard against both the
- * cache expiring from GC and being invalidated by schema context change. The
- * context can change while we are doing processing, so we do not want to block
- * it, so no synchronization can happen on the methods.
- *
- * So what we are doing is the following:
- *
- * We synchronize with GC as usual, using a SoftReference.
- *
- * The atomic reference is used to synchronize with {@link #refresh()}, e.g. when
- * refresh happens, it will push a SoftReference(null), e.g. simulate the GC. Now
- * that may happen while the getter is already busy acting on the old schema context,
- * so it needs to understand that a refresh has happened and retry. To do that, it
- * attempts a CAS operation -- if it fails, in knows that the SoftReference has
- * been replaced and thus it needs to retry.
- *
- * Note that {@link #getYangStoreSnapshot()} will still use synchronize() internally
- * to stop multiple threads doing the same work.
- */
- private final AtomicReference<SoftReference<YangStoreSnapshotImpl>> ref = new AtomicReference<>(new SoftReference<YangStoreSnapshotImpl>(null));
- private final SchemaContextProvider service;
-
- public YangStoreServiceImpl(final SchemaContextProvider service) {
- this.service = service;
- }
-
- @Override
- public synchronized YangStoreSnapshotImpl getYangStoreSnapshot() throws YangStoreException {
- SoftReference<YangStoreSnapshotImpl> r = ref.get();
- YangStoreSnapshotImpl ret = r.get();
-
- while (ret == null) {
- // We need to be compute a new value
- ret = new YangStoreSnapshotImpl(service.getSchemaContext());
-
- if (!ref.compareAndSet(r, new SoftReference<>(ret))) {
- LOG.debug("Concurrent refresh detected, recomputing snapshot");
- r = ref.get();
- ret = null;
- }
- }
-
- return ret;
- }
-
- /**
- * Called when schema context changes, invalidates cache.
- */
- public void refresh() {
- ref.set(new SoftReference<YangStoreSnapshotImpl>(null));
- }
-}
* 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.confignetconfconnector.osgi;
+import com.google.common.collect.Maps;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.controller.config.yangjmxgenerator.PackageTranslator;
+import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
+import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
+import org.opendaylight.yangtools.sal.binding.yang.types.TypeProviderImpl;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class YangStoreSnapshot implements YangStoreContext {
+ private static final Logger LOG = LoggerFactory.getLogger(YangStoreSnapshot.class);
+
+
+ private final Map<String /* Namespace from yang file */,
+ Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> moduleMXBeanEntryMap;
+
+
+ private final Map<QName, Map<String, ModuleMXBeanEntry>> qNamesToIdentitiesToModuleMXBeanEntries;
+
+ private final SchemaContext schemaContext;
+
+ public YangStoreSnapshot(final SchemaContext resolveSchemaContext) {
+ LOG.trace("Resolved modules:{}", resolveSchemaContext.getModules());
+ this.schemaContext = resolveSchemaContext;
+ // JMX generator
+
+ Map<String, String> namespaceToPackageMapping = Maps.newHashMap();
+ PackageTranslator packageTranslator = new PackageTranslator(namespaceToPackageMapping);
+ Map<QName, ServiceInterfaceEntry> qNamesToSIEs = new HashMap<>();
+ Map<IdentitySchemaNode, ServiceInterfaceEntry> knownSEITracker = new HashMap<>();
+ // create SIE structure qNamesToSIEs
+ for (Module module : resolveSchemaContext.getModules()) {
+ String packageName = packageTranslator.getPackageName(module);
+ Map<QName, ServiceInterfaceEntry> namesToSIEntries = ServiceInterfaceEntry
+ .create(module, packageName, knownSEITracker);
+ for (Entry<QName, ServiceInterfaceEntry> sieEntry : namesToSIEntries.entrySet()) {
+ // merge value into qNamesToSIEs
+ if (qNamesToSIEs.containsKey(sieEntry.getKey()) == false) {
+ qNamesToSIEs.put(sieEntry.getKey(), sieEntry.getValue());
+ } else {
+ throw new IllegalStateException("Cannot add two SIE with same qname "
+ + sieEntry.getValue());
+ }
+ }
+ }
+
+ Map<String, Map<String, ModuleMXBeanEntry>> moduleMXBeanEntryMap = Maps.newHashMap();
+
+ Map<QName, Map<String /* identity local name */, ModuleMXBeanEntry>> qNamesToIdentitiesToModuleMXBeanEntries = new HashMap<>();
+
-public interface YangStoreSnapshot extends AutoCloseable {
+ for (Module module : schemaContext.getModules()) {
+ String packageName = packageTranslator.getPackageName(module);
+ TypeProviderWrapper typeProviderWrapper = new TypeProviderWrapper(
+ new TypeProviderImpl(resolveSchemaContext));
- /**
- * @deprecated Use {@link #getQNamesToIdentitiesToModuleMXBeanEntries()} instead. This method return only one
- * module representation even if multiple revisions are available.
- */
- @Deprecated
- Map<String/* Namespace from yang file */,
- Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> getModuleMXBeanEntryMap();
+ QName qName = QName.create(module.getNamespace(), module.getRevision(), module.getName());
+ Map<String /* MB identity local name */, ModuleMXBeanEntry> namesToMBEs =
+ Collections.unmodifiableMap(ModuleMXBeanEntry.create(module, qNamesToSIEs, resolveSchemaContext,
+ typeProviderWrapper, packageName));
+ moduleMXBeanEntryMap.put(module.getNamespace().toString(), namesToMBEs);
+
+ qNamesToIdentitiesToModuleMXBeanEntries.put(qName, namesToMBEs);
+ }
+ this.moduleMXBeanEntryMap = Collections.unmodifiableMap(moduleMXBeanEntryMap);
+ this.qNamesToIdentitiesToModuleMXBeanEntries = Collections.unmodifiableMap(qNamesToIdentitiesToModuleMXBeanEntries);
+
+ }
+
+ @Override
+ public Map<String, Map<String, ModuleMXBeanEntry>> getModuleMXBeanEntryMap() {
+ return moduleMXBeanEntryMap;
+ }
+
+ @Override
+ public Map<QName, Map<String, ModuleMXBeanEntry>> getQNamesToIdentitiesToModuleMXBeanEntries() {
+ return qNamesToIdentitiesToModuleMXBeanEntries;
+ }
+
+ @Override
+ public Set<Module> getModules() {
+ return schemaContext.getModules();
+ }
+
+ @Override
+ public String getModuleSource(final org.opendaylight.yangtools.yang.model.api.ModuleIdentifier moduleIdentifier) {
+ return schemaContext.getModuleSource(moduleIdentifier).get();
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
- Map<QName, Map<String /* identity local name */, ModuleMXBeanEntry>> getQNamesToIdentitiesToModuleMXBeanEntries();
+ final YangStoreSnapshot that = (YangStoreSnapshot) o;
- /**
- * Get all modules discovered when this snapshot was created.
- * @return all modules discovered. If one module exists with two different revisions, return both.
- */
- Set<Module> getModules();
+ if (schemaContext != null ? !schemaContext.equals(that.schemaContext) : that.schemaContext != null)
+ return false;
- String getModuleSource(ModuleIdentifier moduleIdentifier);
+ return true;
+ }
@Override
- void close();
+ public int hashCode() {
+ return schemaContext != null ? schemaContext.hashCode() : 0;
+ }
}
+++ /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.confignetconfconnector.osgi;
-
-import com.google.common.collect.Maps;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
-import org.opendaylight.controller.config.yangjmxgenerator.PackageTranslator;
-import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
-import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
-import org.opendaylight.yangtools.sal.binding.yang.types.TypeProviderImpl;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class YangStoreSnapshotImpl implements YangStoreSnapshot {
- private static final Logger LOG = LoggerFactory.getLogger(YangStoreSnapshotImpl.class);
-
-
- private final Map<String /* Namespace from yang file */,
- Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> moduleMXBeanEntryMap;
-
-
- private final Map<QName, Map<String, ModuleMXBeanEntry>> qNamesToIdentitiesToModuleMXBeanEntries;
-
- private final SchemaContext schemaContext;
-
-
- public YangStoreSnapshotImpl(final SchemaContext resolveSchemaContext) {
- LOG.trace("Resolved modules:{}", resolveSchemaContext.getModules());
- this.schemaContext = resolveSchemaContext;
- // JMX generator
-
- Map<String, String> namespaceToPackageMapping = Maps.newHashMap();
- PackageTranslator packageTranslator = new PackageTranslator(namespaceToPackageMapping);
- Map<QName, ServiceInterfaceEntry> qNamesToSIEs = new HashMap<>();
- Map<IdentitySchemaNode, ServiceInterfaceEntry> knownSEITracker = new HashMap<>();
- // create SIE structure qNamesToSIEs
- for (Module module : resolveSchemaContext.getModules()) {
- String packageName = packageTranslator.getPackageName(module);
- Map<QName, ServiceInterfaceEntry> namesToSIEntries = ServiceInterfaceEntry
- .create(module, packageName, knownSEITracker);
- for (Entry<QName, ServiceInterfaceEntry> sieEntry : namesToSIEntries.entrySet()) {
- // merge value into qNamesToSIEs
- if (qNamesToSIEs.containsKey(sieEntry.getKey()) == false) {
- qNamesToSIEs.put(sieEntry.getKey(), sieEntry.getValue());
- } else {
- throw new IllegalStateException("Cannot add two SIE with same qname "
- + sieEntry.getValue());
- }
- }
- }
-
- Map<String, Map<String, ModuleMXBeanEntry>> moduleMXBeanEntryMap = Maps.newHashMap();
-
- Map<QName, Map<String /* identity local name */, ModuleMXBeanEntry>> qNamesToIdentitiesToModuleMXBeanEntries = new HashMap<>();
-
-
- for (Module module : schemaContext.getModules()) {
- String packageName = packageTranslator.getPackageName(module);
- TypeProviderWrapper typeProviderWrapper = new TypeProviderWrapper(
- new TypeProviderImpl(resolveSchemaContext));
-
- QName qName = QName.create(module.getNamespace(), module.getRevision(), module.getName());
-
- Map<String /* MB identity local name */, ModuleMXBeanEntry> namesToMBEs =
- Collections.unmodifiableMap(ModuleMXBeanEntry.create(module, qNamesToSIEs, resolveSchemaContext,
- typeProviderWrapper, packageName));
- moduleMXBeanEntryMap.put(module.getNamespace().toString(), namesToMBEs);
-
- qNamesToIdentitiesToModuleMXBeanEntries.put(qName, namesToMBEs);
- }
- this.moduleMXBeanEntryMap = Collections.unmodifiableMap(moduleMXBeanEntryMap);
- this.qNamesToIdentitiesToModuleMXBeanEntries = Collections.unmodifiableMap(qNamesToIdentitiesToModuleMXBeanEntries);
-
- }
-
- @Override
- public Map<String, Map<String, ModuleMXBeanEntry>> getModuleMXBeanEntryMap() {
- return moduleMXBeanEntryMap;
- }
-
- @Override
- public Map<QName, Map<String, ModuleMXBeanEntry>> getQNamesToIdentitiesToModuleMXBeanEntries() {
- return qNamesToIdentitiesToModuleMXBeanEntries;
- }
-
- @Override
- public Set<Module> getModules() {
- return schemaContext.getModules();
- }
-
- @Override
- public String getModuleSource(final org.opendaylight.yangtools.yang.model.api.ModuleIdentifier moduleIdentifier) {
- return schemaContext.getModuleSource(moduleIdentifier).get();
- }
-
- @Override
- public void close() {
-
- }
-}
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.get.Get;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc.RuntimeRpc;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreServiceImpl;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
private TestImplModuleFactory factory4;
@Mock
- YangStoreSnapshot yangStoreSnapshot;
+ YangStoreContext yangStoreSnapshot;
@Mock
NetconfOperationRouter netconfOperationRouter;
@Mock
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+
+
+ final Filter filter = mock(Filter.class);
+ doReturn(filter).when(mockedContext).createFilter(anyString());
+ doNothing().when(mockedContext).addServiceListener(any(ServiceListener.class), anyString());
+ doReturn(new ServiceReference<?>[]{}).when(mockedContext).getServiceReferences(anyString(), anyString());
+
doReturn(getMbes()).when(this.yangStoreSnapshot).getModuleMXBeanEntryMap();
doReturn(getModules()).when(this.yangStoreSnapshot).getModules();
doNothing().when(netconfOperationServiceSnapshot).close();
this.factory2 = new DepTestImplModuleFactory();
this.factory3 = new IdentityTestModuleFactory();
factory4 = new TestImplModuleFactory();
+
+
super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, this.factory, this.factory2,
this.factory3, factory4));
YangParserImpl yangParser = new YangParserImpl();
final SchemaContext schemaContext = yangParser.resolveSchemaContext(new HashSet<>(yangParser.parseYangModelsFromStreamsMapped(yangDependencies).values()));
- YangStoreServiceImpl yangStoreService = new YangStoreServiceImpl(new SchemaContextProvider() {
+ YangStoreService yangStoreService = new YangStoreService(new SchemaContextProvider() {
@Override
public SchemaContext getSchemaContext() {
return schemaContext ;
}
- });
- mBeanEntries.putAll(yangStoreService.getYangStoreSnapshot().getModuleMXBeanEntryMap());
+ }, mockedContext);
+ mBeanEntries.putAll(yangStoreService.getModuleMXBeanEntryMap());
return mBeanEntries;
}
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.ValidateTest;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
public class EditConfigTest {
@Mock
- private YangStoreSnapshot yangStoreSnapshot;
+ private YangStoreContext yangStoreSnapshot;
@Mock
private TransactionProvider provider;
@Mock
+++ /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.confignetconfconnector.osgi;
-
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import java.net.URI;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Map;
-import java.util.Set;
-import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
-import org.junit.Test;
-import org.opendaylight.controller.config.api.LookupRegistry;
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
-import org.opendaylight.yangtools.yang.common.QName;
-
-public class NetconfOperationServiceImplTest {
-
- private static final Date date1970_01_01;
-
- static {
- try {
- date1970_01_01 = new SimpleDateFormat("yyyy-MM-dd").parse("1970-01-01");
- } catch (ParseException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Test
- public void testCheckConsistencyBetweenYangStoreAndConfig_ok() throws Exception {
- NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(
- mockJmxClient("qname1", "qname2"),
- mockYangStoreSnapshot("qname2", "qname1"));
- }
-
- @Test
- public void testCheckConsistencyBetweenYangStoreAndConfig_ok2() throws Exception {
- NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(
- mockJmxClient("qname1", "qname2", "qname4", "qname5"),
- mockYangStoreSnapshot("qname2", "qname1"));
- }
-
- @Test
- public void testCheckConsistencyBetweenYangStoreAndConfig_ok3() throws Exception {
- NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(
- mockJmxClient(),
- mockYangStoreSnapshot());
- }
-
- @Test
- public void testCheckConsistencyBetweenYangStoreAndConfig_yangStoreMore() throws Exception {
- try {
- NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(mockJmxClient("qname1"),
- mockYangStoreSnapshot("qname2", "qname1"));
- fail("An exception of type " + IllegalStateException.class + " was expected");
- } catch (IllegalStateException e) {
- String message = e.getMessage();
- Assert.assertThat(
- message,
- CoreMatchers
- .containsString("missing from config subsystem but present in yangstore: [(namespace?revision=1970-01-01)qname2]"));
- Assert.assertThat(
- message,
- CoreMatchers
- .containsString("All modules present in config: [(namespace?revision=1970-01-01)qname1]"));
- }
- }
-
- private YangStoreSnapshot mockYangStoreSnapshot(final String... qnames) {
- YangStoreSnapshot mock = mock(YangStoreSnapshot.class);
-
- Map<String, Map<String, ModuleMXBeanEntry>> map = Maps.newHashMap();
-
- Map<String, ModuleMXBeanEntry> innerMap = Maps.newHashMap();
-
- int i = 1;
- for (String qname : qnames) {
- innerMap.put(Integer.toString(i++), mockMBeanEntry(qname));
- }
-
- map.put("1", innerMap);
-
- doReturn(map).when(mock).getModuleMXBeanEntryMap();
-
- return mock;
- }
-
- private ModuleMXBeanEntry mockMBeanEntry(final String qname) {
- ModuleMXBeanEntry mock = mock(ModuleMXBeanEntry.class);
- QName q = getQName(qname);
- doReturn(q).when(mock).getYangModuleQName();
- return mock;
- }
-
- private QName getQName(final String qname) {
- return QName.create(URI.create("namespace"), date1970_01_01, qname);
- }
-
- private LookupRegistry mockJmxClient(final String... visibleQNames) {
- LookupRegistry mock = mock(LookupRegistry.class);
- Set<String> qnames = Sets.newHashSet();
- for (String visibleQName : visibleQNames) {
- QName q = getQName(visibleQName);
- qnames.add(q.toString());
- }
- doReturn(qnames).when(mock).getAvailableModuleFactoryQNames();
- return mock;
- }
-}
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.mapping.api.SessionAwareNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
if (netconfOperation instanceof DefaultNetconfOperation) {
((DefaultNetconfOperation) netconfOperation).setNetconfSession(session);
}
+ if(netconfOperation instanceof SessionAwareNetconfOperation) {
+ ((SessionAwareNetconfOperation) netconfOperation).setSession(session);
+ }
if (!handlingPriority.equals(HandlingPriority.CANNOT_HANDLE)) {
Preconditions.checkState(!sortedPriority.containsKey(handlingPriority),
import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreServiceImpl;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
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.notifications.BaseNetconfNotificationListener;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
import org.opendaylight.protocol.framework.NeverReconnectStrategy;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
return clientDispatcher;
}
- private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
+ private HardcodedYangStoreService getYangStore() throws IOException {
final Collection<InputStream> yangDependencies = getBasicYangs();
return new HardcodedYangStoreService(yangDependencies);
}
return b.build();
}
- public static final class HardcodedYangStoreService implements YangStoreService {
-
- private final List<InputStream> byteArrayInputStreams;
+ public static final class HardcodedYangStoreService extends YangStoreService {
+ public HardcodedYangStoreService(final Collection<? extends InputStream> inputStreams) throws IOException {
+ super(new SchemaContextProvider() {
+ @Override
+ public SchemaContext getSchemaContext() {
+ return getSchema(inputStreams);
+ }
+ }, new BaseNetconfNotificationListener() {
+ @Override
+ public void onCapabilityChanged(final NetconfCapabilityChange capabilityChange) {
+ // NOOP
+ }
+ });
+ }
- public HardcodedYangStoreService(final Collection<? extends InputStream> inputStreams) throws YangStoreException, IOException {
- byteArrayInputStreams = new ArrayList<>();
+ private static SchemaContext getSchema(final Collection<? extends InputStream> inputStreams) {
+ final ArrayList<InputStream> byteArrayInputStreams = new ArrayList<>();
for (final InputStream inputStream : inputStreams) {
assertNotNull(inputStream);
- final byte[] content = IOUtils.toByteArray(inputStream);
+ final byte[] content;
+ try {
+ content = IOUtils.toByteArray(inputStream);
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot read " + inputStream, e);
+ }
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(content);
byteArrayInputStreams.add(byteArrayInputStream);
}
- }
- @Override
- public YangStoreSnapshot getYangStoreSnapshot() throws YangStoreException {
for (final InputStream inputStream : byteArrayInputStreams) {
try {
inputStream.reset();
}
final YangParserImpl yangParser = new YangParserImpl();
- final SchemaContext schemaContext = yangParser.resolveSchemaContext(new HashSet<>(yangParser.parseYangModelsFromStreamsMapped(byteArrayInputStreams).values()));
- final YangStoreServiceImpl yangStoreService = new YangStoreServiceImpl(new SchemaContextProvider() {
- @Override
- public SchemaContext getSchemaContext() {
- return schemaContext ;
- }
- });
- return yangStoreService.getYangStoreSnapshot();
+ return yangParser.resolveSchemaContext(new HashSet<>(yangParser.parseYangModelsFromStreamsMapped(byteArrayInputStreams).values()));
}
}
}