From: Tony Tkacik Date: Fri, 28 Mar 2014 19:13:21 +0000 (+0000) Subject: Merge "Resolve Bug:593. Persister should communicate via OSGi SR instead of TCP." X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~302 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=d5759c52d69ba8725d9bbdc18e81848f319861d1;hp=af0a694833f73b82d4ccd4ec035e1de19807fb33 Merge "Resolve Bug:593. Persister should communicate via OSGi SR instead of TCP." --- diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java index 308b137403..6381836af8 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java @@ -14,9 +14,7 @@ import org.opendaylight.controller.config.manager.impl.osgi.mapping.ModuleInfoBu import org.opendaylight.controller.config.manager.impl.osgi.mapping.RefreshingSCPModuleInfoRegistry; import org.opendaylight.controller.config.manager.impl.util.OsgiRegistrationUtil; import org.opendaylight.controller.config.spi.ModuleFactory; -import org.opendaylight.yangtools.concepts.ObjectRegistration; import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; -import org.opendaylight.yangtools.yang.binding.YangModuleInfo; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.util.tracker.ServiceTracker; @@ -25,7 +23,6 @@ import javax.management.InstanceAlreadyExistsException; import javax.management.MBeanServer; import java.lang.management.ManagementFactory; import java.util.Arrays; -import java.util.Collection; import java.util.List; import static org.opendaylight.controller.config.manager.impl.util.OsgiRegistrationUtil.registerService; @@ -57,11 +54,12 @@ public class ConfigManagerActivator implements BundleActivator { // track bundles containing factories BlankTransactionServiceTracker blankTransactionServiceTracker = new BlankTransactionServiceTracker( configRegistry); - ModuleFactoryBundleTracker moduleFactoryBundleTracker = new ModuleFactoryBundleTracker( + ModuleFactoryBundleTracker primaryModuleFactoryBundleTracker = new ModuleFactoryBundleTracker( blankTransactionServiceTracker); // start extensible tracker - ExtensibleBundleTracker>> bundleTracker = new ExtensibleBundleTracker<>(context, moduleInfoBundleTracker, moduleFactoryBundleTracker); + ExtensibleBundleTracker bundleTracker = new ExtensibleBundleTracker<>(context, + primaryModuleFactoryBundleTracker, moduleInfoBundleTracker); bundleTracker.open(); // register config registry to OSGi diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/Activator.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/Activator.java index b39549ed5b..421870ca36 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/Activator.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/Activator.java @@ -19,6 +19,9 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Dictionary; +import java.util.Hashtable; + import static com.google.common.base.Preconditions.checkState; public class Activator implements BundleActivator { @@ -88,7 +91,9 @@ public class Activator implements BundleActivator { public void run() { NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService); logger.debug("Registering into OSGi"); - osgiRegistration = context.registerService(NetconfOperationServiceFactory.class, factory, null); + Dictionary properties = new Hashtable<>(); + properties.put("name", "config-netconf-connector"); + osgiRegistration = context.registerService(NetconfOperationServiceFactory.class, factory, properties); } } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceFactoryImpl.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceFactoryImpl.java index 4ca71ae288..b8b7fcb47f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceFactoryImpl.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceFactoryImpl.java @@ -66,7 +66,7 @@ public class NetconfOperationServiceFactoryImpl implements NetconfOperationServi } @Override - public NetconfOperationServiceImpl createService(long netconfSessionId, String netconfSessionIdForReporting) { + public NetconfOperationServiceImpl createService(String netconfSessionIdForReporting) { try { return new NetconfOperationServiceImpl(yangStoreService, jmxClient, netconfSessionIdForReporting); } catch (YangStoreException e) { diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java index b52328f631..8b6b1aefc1 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java @@ -52,10 +52,10 @@ import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStore 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.NetconfOperationRouterImpl; import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot; import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; import org.opendaylight.controller.netconf.mapping.api.NetconfOperation; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution; import org.opendaylight.controller.netconf.util.test.XmlFileLoader; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; @@ -681,7 +681,7 @@ public class NetconfMappingTest extends AbstractConfigTest { Preconditions.checkState(priority != HandlingPriority.CANNOT_HANDLE); - final Document response = op.handle(request, NetconfOperationRouterImpl.EXECUTION_TERMINATION_POINT); + final Document response = op.handle(request, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT); logger.debug("Got response\n{}", XmlUtil.toString(response)); return response.getDocumentElement(); } diff --git a/opendaylight/netconf/config-persister-impl/pom.xml b/opendaylight/netconf/config-persister-impl/pom.xml index c0b9f68814..7b4511e1f9 100644 --- a/opendaylight/netconf/config-persister-impl/pom.xml +++ b/opendaylight/netconf/config-persister-impl/pom.xml @@ -20,10 +20,6 @@ ${project.groupId} netconf-api - - ${project.groupId} - netconf-client - ${project.groupId} netconf-util @@ -61,6 +57,7 @@ org.opendaylight.yangtools mockito-configuration + test commons-io @@ -83,32 +80,7 @@ org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator - org.opendaylight.controller.config.persister.storage.adapter - - - com.google.common.base, - com.google.common.collect, - javax.management, - javax.xml.parsers, - org.opendaylight.controller.config.persist.api, - org.opendaylight.controller.netconf.api, - org.opendaylight.controller.netconf.api.jmx, - org.opendaylight.controller.netconf.client, - org.opendaylight.controller.netconf.util.osgi, - org.opendaylight.controller.netconf.util.xml, - org.opendaylight.controller.netconf.util.messages, - io.netty.channel, - io.netty.channel.nio, - io.netty.util.concurrent, - org.osgi.framework, - org.slf4j, - org.w3c.dom, - org.xml.sax, - javax.xml.namespace, - javax.xml.xpath, - org.opendaylight.controller.config.api, - org.opendaylight.controller.netconf.util - + org.opendaylight.controller.config.persister.storage.adapter diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolder.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolder.java index d9c5dfaded..ab353e349b 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolder.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolder.java @@ -5,6 +5,7 @@ * 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.persist.impl; import com.google.common.annotations.VisibleForTesting; @@ -18,54 +19,50 @@ import org.w3c.dom.Element; import java.util.Collections; import java.util.HashSet; -import java.util.Iterator; import java.util.Map.Entry; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; -import java.util.regex.Pattern; - -import static com.google.common.base.Preconditions.checkState; +/** + * Inspects snapshot xml to be stored, remove all capabilities that are not referenced by it. + * Useful when persisting current configuration. + */ public class CapabilityStrippingConfigSnapshotHolder implements ConfigSnapshotHolder { private static final Logger logger = LoggerFactory.getLogger(CapabilityStrippingConfigSnapshotHolder.class); private final String configSnapshot; private final StripCapabilitiesResult stripCapabilitiesResult; - public CapabilityStrippingConfigSnapshotHolder(Element snapshot, Set capabilities, Pattern ignoredMissingCapabilityRegex) { + public CapabilityStrippingConfigSnapshotHolder(Element snapshot, Set capabilities) { final XmlElement configElement = XmlElement.fromDomElement(snapshot); configSnapshot = XmlUtil.toString(configElement.getDomElement()); - stripCapabilitiesResult = stripCapabilities(configElement, capabilities, ignoredMissingCapabilityRegex); + stripCapabilitiesResult = stripCapabilities(configElement, capabilities); } private static class StripCapabilitiesResult { - private final SortedSet requiredCapabilities, missingNamespaces; + private final SortedSet requiredCapabilities, obsoleteCapabilities; - private StripCapabilitiesResult(SortedSet requiredCapabilities, SortedSet missingNamespaces) { + private StripCapabilitiesResult(SortedSet requiredCapabilities, SortedSet obsoleteCapabilities) { this.requiredCapabilities = Collections.unmodifiableSortedSet(requiredCapabilities); - this.missingNamespaces = Collections.unmodifiableSortedSet(missingNamespaces); + this.obsoleteCapabilities = Collections.unmodifiableSortedSet(obsoleteCapabilities); } } @VisibleForTesting - static StripCapabilitiesResult stripCapabilities(XmlElement configElement, Set allCapabilitiesFromHello, - Pattern ignoredMissingCapabilityRegex) { + static StripCapabilitiesResult stripCapabilities(XmlElement configElement, Set allCapabilitiesFromHello) { // collect all namespaces Set foundNamespacesInXML = getNamespaces(configElement); logger.trace("All capabilities {}\nFound namespaces in XML {}", allCapabilitiesFromHello, foundNamespacesInXML); // required are referenced both in xml and hello SortedSet requiredCapabilities = new TreeSet<>(); // can be removed - Set obsoleteCapabilities = new HashSet<>(); - // are in xml but not in hello - SortedSet missingNamespaces = new TreeSet<>(foundNamespacesInXML); + SortedSet obsoleteCapabilities = new TreeSet<>(); for (String capability : allCapabilitiesFromHello) { String namespace = capability.replaceAll("\\?.*",""); if (foundNamespacesInXML.contains(namespace)) { requiredCapabilities.add(capability); - checkState(missingNamespaces.remove(namespace)); } else { obsoleteCapabilities.add(capability); } @@ -74,17 +71,7 @@ public class CapabilityStrippingConfigSnapshotHolder implements ConfigSnapshotHo logger.trace("Required capabilities {}, \nObsolete capabilities {}", requiredCapabilities, obsoleteCapabilities); - for(Iterator iterator = missingNamespaces.iterator();iterator.hasNext(); ){ - String capability = iterator.next(); - if (ignoredMissingCapabilityRegex.matcher(capability).matches()){ - logger.trace("Ignoring missing capability {}", capability); - iterator.remove(); - } - } - if (missingNamespaces.size() > 0) { - logger.warn("Some capabilities are missing: {}", missingNamespaces); - } - return new StripCapabilitiesResult(requiredCapabilities, missingNamespaces); + return new StripCapabilitiesResult(requiredCapabilities, obsoleteCapabilities); } static Set getNamespaces(XmlElement element){ @@ -94,7 +81,6 @@ public class CapabilityStrippingConfigSnapshotHolder implements ConfigSnapshotHo result.add(attribute.getValue().getValue()); } } - //element.getAttributes() for(XmlElement child: element.getChildElements()) { result.addAll(getNamespaces(child)); } @@ -107,8 +93,8 @@ public class CapabilityStrippingConfigSnapshotHolder implements ConfigSnapshotHo } @VisibleForTesting - Set getMissingNamespaces(){ - return stripCapabilitiesResult.missingNamespaces; + Set getObsoleteCapabilities(){ + return stripCapabilitiesResult.obsoleteCapabilities; } @Override diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java index 2d89bbc55c..eb6fd2722a 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java @@ -23,7 +23,6 @@ import javax.management.NotificationListener; import javax.management.ObjectName; import java.io.Closeable; import java.io.IOException; -import java.util.regex.Pattern; /** * Responsible for listening for notifications from netconf (via JMX) containing latest @@ -39,9 +38,9 @@ public class ConfigPersisterNotificationHandler implements Closeable { public ConfigPersisterNotificationHandler(MBeanServerConnection mBeanServerConnection, - Persister persisterAggregator, Pattern ignoredMissingCapabilityRegex) { + Persister persisterAggregator) { this.mBeanServerConnection = mBeanServerConnection; - listener = new ConfigPersisterNotificationListener(persisterAggregator, ignoredMissingCapabilityRegex); + listener = new ConfigPersisterNotificationListener(persisterAggregator); registerAsJMXListener(mBeanServerConnection, listener); } @@ -73,17 +72,16 @@ class ConfigPersisterNotificationListener implements NotificationListener { private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationListener.class); private final Persister persisterAggregator; - private final Pattern ignoredMissingCapabilityRegex; - ConfigPersisterNotificationListener(Persister persisterAggregator, Pattern ignoredMissingCapabilityRegex) { + ConfigPersisterNotificationListener(Persister persisterAggregator) { this.persisterAggregator = persisterAggregator; - this.ignoredMissingCapabilityRegex = ignoredMissingCapabilityRegex; } @Override public void handleNotification(Notification notification, Object handback) { - if (notification instanceof NetconfJMXNotification == false) + if (notification instanceof NetconfJMXNotification == false) { return; + } // Socket should not be closed at this point // Activator unregisters this as JMX listener before close is called @@ -98,14 +96,15 @@ class ConfigPersisterNotificationListener implements NotificationListener { logger.warn("Exception occured during notification handling: ", e); throw e; } - } else + } else { throw new IllegalStateException("Unknown config registry notification type " + notification); + } } private void handleAfterCommitNotification(final CommitJMXNotification notification) { try { persisterAggregator.persistConfig(new CapabilityStrippingConfigSnapshotHolder(notification.getConfigSnapshot(), - notification.getCapabilities(), ignoredMissingCapabilityRegex)); + notification.getCapabilities())); logger.trace("Configuration persisted successfully"); } catch (IOException e) { throw new RuntimeException("Unable to persist configuration snapshot", e); diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java index ea2a46dba5..6dba9ac64e 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java @@ -8,14 +8,21 @@ package org.opendaylight.controller.netconf.persist.impl; +import com.google.common.base.Function; import com.google.common.base.Preconditions; +import com.google.common.base.Stopwatch; +import com.google.common.collect.Collections2; import org.opendaylight.controller.config.api.ConflictingVersionException; import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.controller.netconf.client.NetconfClient; -import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; +import org.opendaylight.controller.netconf.mapping.api.Capability; +import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; +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.NetconfOperationServiceFactory; import org.opendaylight.controller.netconf.util.NetconfUtil; -import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -28,38 +35,36 @@ import org.xml.sax.SAXException; import javax.annotation.concurrent.Immutable; import java.io.IOException; import java.io.InputStream; -import java.util.Collections; +import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; +import java.util.Map.Entry; import java.util.Set; -import java.util.concurrent.ExecutionException; +import java.util.TreeMap; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; @Immutable public class ConfigPusher { private static final Logger logger = LoggerFactory.getLogger(ConfigPusher.class); - private final ConfigPusherConfiguration configuration; + private final long maxWaitForCapabilitiesMillis; + private final long conflictingVersionTimeoutMillis; + private final NetconfOperationServiceFactory configNetconfConnector; - public ConfigPusher(ConfigPusherConfiguration configuration) { - this.configuration = configuration; + public ConfigPusher(NetconfOperationServiceFactory configNetconfConnector, long maxWaitForCapabilitiesMillis, + long conflictingVersionTimeoutMillis) { + this.configNetconfConnector = configNetconfConnector; + this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis; + this.conflictingVersionTimeoutMillis = conflictingVersionTimeoutMillis; } - public synchronized LinkedHashMap pushConfigs( - List configs) throws InterruptedException { + public synchronized LinkedHashMap pushConfigs(List configs) { logger.debug("Last config snapshots to be pushed to netconf: {}", configs); - - // first just make sure we can connect to netconf, even if nothing is being pushed - { - NetconfClient netconfClient = makeNetconfConnection(Collections.emptySet()); - Util.closeClientAndDispatcher(netconfClient); - } - LinkedHashMap result = new LinkedHashMap<>(); + LinkedHashMap result = new LinkedHashMap<>(); // start pushing snapshots: for (ConfigSnapshotHolder configSnapshotHolder : configs) { - EditAndCommitResponseWithRetries editAndCommitResponseWithRetries = pushSnapshotWithRetries(configSnapshotHolder); + EditAndCommitResponse editAndCommitResponseWithRetries = pushConfigWithConflictingVersionRetries(configSnapshotHolder); logger.debug("Config snapshot pushed successfully: {}, result: {}", configSnapshotHolder, result); result.put(configSnapshotHolder, editAndCommitResponseWithRetries); } @@ -68,106 +73,101 @@ public class ConfigPusher { } /** - * Checks for ConflictingVersionException and retries until optimistic lock succeeds or maximal - * number of attempts is reached. + * First calls {@link #getOperationServiceWithRetries(java.util.Set, String)} in order to wait until + * expected capabilities are present, then tries to push configuration. If {@link ConflictingVersionException} + * is caught, whole process is retried - new service instance need to be obtained from the factory. Closes + * {@link NetconfOperationService} after each use. */ - private synchronized EditAndCommitResponseWithRetries pushSnapshotWithRetries(ConfigSnapshotHolder configSnapshotHolder) - throws InterruptedException { - - ConflictingVersionException lastException = null; - int maxAttempts = configuration.netconfPushConfigAttempts; - - for (int retryAttempt = 1; retryAttempt <= maxAttempts; retryAttempt++) { - NetconfClient netconfClient = makeNetconfConnection(configSnapshotHolder.getCapabilities()); - logger.trace("Pushing following xml to netconf {}", configSnapshotHolder); - try { - EditAndCommitResponse editAndCommitResponse = pushLastConfig(configSnapshotHolder, netconfClient); - return new EditAndCommitResponseWithRetries(editAndCommitResponse, retryAttempt); + private synchronized EditAndCommitResponse pushConfigWithConflictingVersionRetries(ConfigSnapshotHolder configSnapshotHolder) { + ConflictingVersionException lastException; + Stopwatch stopwatch = new Stopwatch().start(); + do { + try (NetconfOperationService operationService = getOperationServiceWithRetries(configSnapshotHolder.getCapabilities(), configSnapshotHolder.toString())) { + return pushConfig(configSnapshotHolder, operationService); } catch (ConflictingVersionException e) { - logger.debug("Conflicting version detected, will retry after timeout"); lastException = e; - Thread.sleep(configuration.netconfPushConfigDelayMs); - } catch (RuntimeException e) { - throw new IllegalStateException("Unable to load " + configSnapshotHolder, e); - } finally { - Util.closeClientAndDispatcher(netconfClient); + logger.debug("Conflicting version detected, will retry after timeout"); + sleep(); } - } - throw new IllegalStateException("Maximum attempt count has been reached for pushing " + configSnapshotHolder, + } while (stopwatch.elapsed(TimeUnit.MILLISECONDS) < conflictingVersionTimeoutMillis); + throw new IllegalStateException("Max wait for conflicting version stabilization timeout after " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms", lastException); } - /** - * @param expectedCaps capabilities that server hello must contain. Will retry until all are found or throws RuntimeException. - * If empty set is provided, will only make sure netconf client successfuly connected to the server. - * @return NetconfClient that has all required capabilities from server. - */ - private synchronized NetconfClient makeNetconfConnection(Set expectedCaps) throws InterruptedException { - - // TODO think about moving capability subset check to netconf client - // could be utilized by integration tests - - final long pollingStartNanos = System.nanoTime(); - final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(configuration.netconfCapabilitiesWaitTimeoutMs); - int attempt = 0; - - NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("unknown", - configuration.netconfAddress.getAddress().getHostAddress(), - Integer.toString(configuration.netconfAddress.getPort()), "tcp", "persister"); - - Set latestCapabilities = null; - while (System.nanoTime() < deadlineNanos) { - attempt++; - NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(configuration.eventLoopGroup, - configuration.eventLoopGroup, additionalHeader, configuration.connectionAttemptTimeoutMs); - NetconfClient netconfClient; + private NetconfOperationService getOperationServiceWithRetries(Set expectedCapabilities, String idForReporting) { + Stopwatch stopwatch = new Stopwatch().start(); + NotEnoughCapabilitiesException lastException; + do { try { - netconfClient = new NetconfClient(this.toString(), configuration.netconfAddress, configuration.connectionAttemptDelayMs, netconfClientDispatcher); - } catch (IllegalStateException e) { - logger.debug("Netconf {} was not initialized or is not stable, attempt {}", configuration.netconfAddress, attempt, e); - netconfClientDispatcher.close(); - Thread.sleep(configuration.connectionAttemptDelayMs); - continue; - } - latestCapabilities = netconfClient.getCapabilities(); - if (Util.isSubset(netconfClient, expectedCaps)) { - logger.debug("Hello from netconf stable with {} capabilities", latestCapabilities); - logger.trace("Session id received from netconf server: {}", netconfClient.getClientSession()); - return netconfClient; + return getOperationService(expectedCapabilities, idForReporting); + } catch (NotEnoughCapabilitiesException e) { + logger.debug("Not enough capabilities: " + e.toString()); + lastException = e; + sleep(); } - Set allNotFound = computeNotFoundCapabilities(expectedCaps, latestCapabilities); - logger.debug("Netconf server did not provide required capabilities. Attempt {}. " + - "Expected but not found: {}, all expected {}, current {}", - attempt, allNotFound, expectedCaps, latestCapabilities); - Util.closeClientAndDispatcher(netconfClient); - Thread.sleep(configuration.connectionAttemptDelayMs); + } while (stopwatch.elapsed(TimeUnit.MILLISECONDS) < maxWaitForCapabilitiesMillis); + throw new IllegalStateException("Max wait for capabilities reached." + lastException.getMessage(), lastException); + } + + private static class NotEnoughCapabilitiesException extends Exception { + private NotEnoughCapabilitiesException(String message) { + super(message); } - if (latestCapabilities == null) { - logger.error("Could not connect to the server in {} ms", configuration.netconfCapabilitiesWaitTimeoutMs); - throw new RuntimeException("Could not connect to netconf server"); + } + + /** + * Get NetconfOperationService iif all required capabilities are present. + * + * @param expectedCapabilities that must be provided by configNetconfConnector + * @param idForReporting + * @return service if capabilities are present, otherwise absent value + */ + private NetconfOperationService getOperationService(Set expectedCapabilities, String idForReporting) throws NotEnoughCapabilitiesException { + NetconfOperationService serviceCandidate = configNetconfConnector.createService(idForReporting); + Set notFoundDiff = computeNotFoundCapabilities(expectedCapabilities, serviceCandidate); + if (notFoundDiff.isEmpty()) { + return serviceCandidate; + } else { + serviceCandidate.close(); + logger.debug("Netconf server did not provide required capabilities for {} " + + "Expected but not found: {}, all expected {}, current {}", + idForReporting, notFoundDiff, expectedCapabilities, serviceCandidate.getCapabilities() + ); + throw new NotEnoughCapabilitiesException("Not enough capabilities for " + idForReporting + ". Expected but not found: " + notFoundDiff); } - Set allNotFound = computeNotFoundCapabilities(expectedCaps, latestCapabilities); - logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}", - allNotFound, expectedCaps, latestCapabilities); - throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound); } - private static Set computeNotFoundCapabilities(Set expectedCaps, Set latestCapabilities) { - Set allNotFound = new HashSet<>(expectedCaps); - allNotFound.removeAll(latestCapabilities); + private static Set computeNotFoundCapabilities(Set expectedCapabilities, NetconfOperationService serviceCandidate) { + Collection actual = Collections2.transform(serviceCandidate.getCapabilities(), new Function() { + @Override + public String apply(Capability input) { + return input.getCapabilityUri(); + } + }); + Set allNotFound = new HashSet<>(expectedCapabilities); + allNotFound.removeAll(actual); return allNotFound; } + + private void sleep() { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(e); + } + } + /** * Sends two RPCs to the netconf server: edit-config and commit. * * @param configSnapshotHolder - * @param netconfClient * @throws ConflictingVersionException if commit fails on optimistic lock failure inside of config-manager * @throws java.lang.RuntimeException if edit-config or commit fails otherwise */ - private synchronized EditAndCommitResponse pushLastConfig(ConfigSnapshotHolder configSnapshotHolder, NetconfClient netconfClient) + private synchronized EditAndCommitResponse pushConfig(ConfigSnapshotHolder configSnapshotHolder, NetconfOperationService operationService) throws ConflictingVersionException { Element xmlToBePersisted; @@ -177,56 +177,66 @@ public class ConfigPusher { throw new IllegalStateException("Cannot parse " + configSnapshotHolder); } logger.trace("Pushing last configuration to netconf: {}", configSnapshotHolder); - + Stopwatch stopwatch = new Stopwatch().start(); NetconfMessage editConfigMessage = createEditConfigMessage(xmlToBePersisted); - // sending message to netconf - NetconfMessage editResponseMessage; - try { - editResponseMessage = sendRequestGetResponseCheckIsOK(editConfigMessage, netconfClient); - } catch (IOException e) { - throw new IllegalStateException("Edit-config failed on " + configSnapshotHolder, e); - } + Document editResponseMessage = sendRequestGetResponseCheckIsOK(editConfigMessage, operationService, + "edit-config", configSnapshotHolder.toString()); - // commit - NetconfMessage commitResponseMessage; - try { - commitResponseMessage = sendRequestGetResponseCheckIsOK(getCommitMessage(), netconfClient); - } catch (IOException e) { - throw new IllegalStateException("Edit commit succeeded, but commit failed on " + configSnapshotHolder, e); - } + Document commitResponseMessage = sendRequestGetResponseCheckIsOK(getCommitMessage(), operationService, + "commit", configSnapshotHolder.toString()); if (logger.isTraceEnabled()) { StringBuilder response = new StringBuilder("editConfig response = {"); - response.append(XmlUtil.toString(editResponseMessage.getDocument())); + response.append(XmlUtil.toString(editResponseMessage)); response.append("}"); response.append("commit response = {"); - response.append(XmlUtil.toString(commitResponseMessage.getDocument())); + response.append(XmlUtil.toString(commitResponseMessage)); response.append("}"); logger.trace("Last configuration loaded successfully"); logger.trace("Detailed message {}", response); + logger.trace("Total time spent {} ms", stopwatch.elapsed(TimeUnit.MILLISECONDS)); } return new EditAndCommitResponse(editResponseMessage, commitResponseMessage); } + private NetconfOperation findOperation(NetconfMessage request, NetconfOperationService operationService) { + TreeMap allOperations = new TreeMap<>(); + Set netconfOperations = operationService.getNetconfOperations(); + if (netconfOperations.isEmpty()) { + throw new IllegalStateException("Possible code error: no config operations"); + } + for (NetconfOperation netconfOperation : netconfOperations) { + HandlingPriority handlingPriority = netconfOperation.canHandle(request.getDocument()); + allOperations.put(handlingPriority, netconfOperation); + } + Entry highestEntry = allOperations.lastEntry(); + if (highestEntry.getKey().isCannotHandle()) { + throw new IllegalStateException("Possible code error: operation with highest priority is CANNOT_HANDLE"); + } + return highestEntry.getValue(); + } + + private Document sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfOperationService operationService, + String operationNameForReporting, String configIdForReporting) + throws ConflictingVersionException { - private NetconfMessage sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfClient netconfClient) - throws ConflictingVersionException, IOException { + NetconfOperation operation = findOperation(request, operationService); + Document response; try { - NetconfMessage netconfMessage = netconfClient.sendMessage(request, - configuration.netconfSendMessageMaxAttempts, configuration.netconfSendMessageDelayMs); - NetconfUtil.checkIsMessageOk(netconfMessage); - return netconfMessage; - } catch(ConflictingVersionException e) { - logger.trace("conflicting version detected: {}", e.toString()); + response = operation.handle(request.getDocument(), NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT); + } catch (NetconfDocumentedException | RuntimeException e) { + throw new IllegalStateException("Failed to send " + operationNameForReporting + + " for configuration " + configIdForReporting, e); + } + try { + return NetconfUtil.checkIsMessageOk(response); + } catch (ConflictingVersionException e) { + logger.trace("conflicting version detected: {} while committing {}", e.toString(), configIdForReporting); throw e; - } catch (RuntimeException | ExecutionException | InterruptedException | TimeoutException e) { // TODO: change NetconfClient#sendMessage to throw checked exceptions - logger.debug("Error while executing netconf transaction {} to {}", request, netconfClient, e); - throw new IOException("Failed to execute netconf transaction", e); } } - // load editConfig.xml template, populate /rpc/edit-config/config with parameter private static NetconfMessage createEditConfigMessage(Element dataElement) { String editConfigResourcePath = "/netconfOp/editConfig.xml"; @@ -246,7 +256,7 @@ public class ConfigPusher { return new NetconfMessage(doc); } catch (IOException | SAXException e) { // error reading the xml file bundled into the jar - throw new RuntimeException("Error while opening local resource " + editConfigResourcePath, e); + throw new IllegalStateException("Error while opening local resource " + editConfigResourcePath, e); } } @@ -257,23 +267,23 @@ public class ConfigPusher { return new NetconfMessage(XmlUtil.readXmlToDocument(stream)); } catch (SAXException | IOException e) { // error reading the xml file bundled into the jar - throw new RuntimeException("Error while opening local resource " + resource, e); + throw new IllegalStateException("Error while opening local resource " + resource, e); } } static class EditAndCommitResponse { - private final NetconfMessage editResponse, commitResponse; + private final Document editResponse, commitResponse; - EditAndCommitResponse(NetconfMessage editResponse, NetconfMessage commitResponse) { + EditAndCommitResponse(Document editResponse, Document commitResponse) { this.editResponse = editResponse; this.commitResponse = commitResponse; } - public NetconfMessage getEditResponse() { + public Document getEditResponse() { return editResponse; } - public NetconfMessage getCommitResponse() { + public Document getCommitResponse() { return commitResponse; } @@ -285,32 +295,4 @@ public class ConfigPusher { '}'; } } - - - static class EditAndCommitResponseWithRetries { - private final EditAndCommitResponse editAndCommitResponse; - private final int retries; - - EditAndCommitResponseWithRetries(EditAndCommitResponse editAndCommitResponse, int retries) { - this.editAndCommitResponse = editAndCommitResponse; - this.retries = retries; - } - - public int getRetries() { - return retries; - } - - public EditAndCommitResponse getEditAndCommitResponse() { - return editAndCommitResponse; - } - - @Override - public String toString() { - return "EditAndCommitResponseWithRetries{" + - "editAndCommitResponse=" + editAndCommitResponse + - ", retries=" + retries + - '}'; - } - } - } diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfiguration.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfiguration.java deleted file mode 100644 index aa189f06b4..0000000000 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfiguration.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.persist.impl; - -import io.netty.channel.EventLoopGroup; - -import javax.annotation.concurrent.Immutable; -import java.net.InetSocketAddress; -import java.util.concurrent.TimeUnit; - -/** - * Configuration properties for ConfigPusher. Contains delays and timeouts for netconf - * connection establishment, netconf capabilities stabilization and configuration push. - */ -@Immutable -public final class ConfigPusherConfiguration { - - public static final long DEFAULT_CONNECTION_ATTEMPT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5); - public static final int DEFAULT_CONNECTION_ATTEMPT_DELAY_MS = 5000; - - public static final int DEFAULT_NETCONF_SEND_MESSAGE_MAX_ATTEMPTS = 20; - public static final int DEFAULT_NETCONF_SEND_MESSAGE_DELAY_MS = 1000; - - public static final long DEFAULT_NETCONF_CAPABILITIES_WAIT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(2); - - public static final int DEFAULT_NETCONF_PUSH_CONFIG_ATTEMPTS = 30; - public static final long DEFAULT_NETCONF_PUSH_CONFIG_DELAY_MS = TimeUnit.MINUTES.toMillis(1); - - final InetSocketAddress netconfAddress; - final EventLoopGroup eventLoopGroup; - - /** - * Total time to wait for capability stabilization - */ - final long netconfCapabilitiesWaitTimeoutMs; - - /** - * Delay between message send attempts - */ - final int netconfSendMessageDelayMs; - /** - * Total number attempts to send a message - */ - final int netconfSendMessageMaxAttempts; - - /** - * Delay between connection establishment attempts - */ - final int connectionAttemptDelayMs; - /** - * Total number of attempts to perform connection establishment - */ - final long connectionAttemptTimeoutMs; - - /** - * Total number of attempts to push configuration to netconf - */ - final int netconfPushConfigAttempts; - /** - * Delay between configuration push attempts - */ - final long netconfPushConfigDelayMs; - - ConfigPusherConfiguration(InetSocketAddress netconfAddress, long netconfCapabilitiesWaitTimeoutMs, - int netconfSendMessageDelayMs, int netconfSendMessageMaxAttempts, int connectionAttemptDelayMs, - long connectionAttemptTimeoutMs, EventLoopGroup eventLoopGroup, int netconfPushConfigAttempts, - long netconfPushConfigDelayMs) { - this.netconfAddress = netconfAddress; - this.netconfCapabilitiesWaitTimeoutMs = netconfCapabilitiesWaitTimeoutMs; - this.netconfSendMessageDelayMs = netconfSendMessageDelayMs; - this.netconfSendMessageMaxAttempts = netconfSendMessageMaxAttempts; - this.connectionAttemptDelayMs = connectionAttemptDelayMs; - this.connectionAttemptTimeoutMs = connectionAttemptTimeoutMs; - this.eventLoopGroup = eventLoopGroup; - this.netconfPushConfigAttempts = netconfPushConfigAttempts; - this.netconfPushConfigDelayMs = netconfPushConfigDelayMs; - } -} diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java deleted file mode 100644 index c26dc8dbe1..0000000000 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.persist.impl; - -import io.netty.channel.EventLoopGroup; - -import java.net.InetSocketAddress; - -public class ConfigPusherConfigurationBuilder { - InetSocketAddress netconfAddress; - EventLoopGroup eventLoopGroup; - - long netconfCapabilitiesWaitTimeoutMs = ConfigPusherConfiguration.DEFAULT_NETCONF_CAPABILITIES_WAIT_TIMEOUT_MS; - int netconfSendMessageDelayMs = ConfigPusherConfiguration.DEFAULT_NETCONF_SEND_MESSAGE_DELAY_MS; - int netconfSendMessageMaxAttempts = ConfigPusherConfiguration.DEFAULT_NETCONF_SEND_MESSAGE_MAX_ATTEMPTS; - int connectionAttemptDelayMs = ConfigPusherConfiguration.DEFAULT_CONNECTION_ATTEMPT_DELAY_MS; - long connectionAttemptTimeoutMs = ConfigPusherConfiguration.DEFAULT_CONNECTION_ATTEMPT_TIMEOUT_MS; - int netconfPushConfigAttempts = ConfigPusherConfiguration.DEFAULT_NETCONF_PUSH_CONFIG_ATTEMPTS; - long netconfPushConfigDelayMs = ConfigPusherConfiguration.DEFAULT_NETCONF_PUSH_CONFIG_DELAY_MS; - - private ConfigPusherConfigurationBuilder() { - } - - public static ConfigPusherConfigurationBuilder aConfigPusherConfiguration() { - return new ConfigPusherConfigurationBuilder(); - } - - public ConfigPusherConfigurationBuilder withNetconfAddress(InetSocketAddress netconfAddress) { - this.netconfAddress = netconfAddress; - return this; - } - - public ConfigPusherConfigurationBuilder withNetconfCapabilitiesWaitTimeoutMs(long netconfCapabilitiesWaitTimeoutMs) { - this.netconfCapabilitiesWaitTimeoutMs = netconfCapabilitiesWaitTimeoutMs; - return this; - } - - public ConfigPusherConfigurationBuilder withNetconfSendMessageDelayMs(int netconfSendMessageDelayMs) { - this.netconfSendMessageDelayMs = netconfSendMessageDelayMs; - return this; - } - - public ConfigPusherConfigurationBuilder withNetconfSendMessageMaxAttempts(int netconfSendMessageMaxAttempts) { - this.netconfSendMessageMaxAttempts = netconfSendMessageMaxAttempts; - return this; - } - - public ConfigPusherConfigurationBuilder withConnectionAttemptDelayMs(int connectionAttemptDelayMs) { - this.connectionAttemptDelayMs = connectionAttemptDelayMs; - return this; - } - - public ConfigPusherConfigurationBuilder withConnectionAttemptTimeoutMs(long connectionAttemptTimeoutMs) { - this.connectionAttemptTimeoutMs = connectionAttemptTimeoutMs; - return this; - } - - public ConfigPusherConfigurationBuilder withEventLoopGroup(EventLoopGroup eventLoopGroup) { - this.eventLoopGroup = eventLoopGroup; - return this; - } - - public ConfigPusherConfigurationBuilder withNetconfPushConfigAttempts(int netconfPushConfigAttempts) { - this.netconfPushConfigAttempts = netconfPushConfigAttempts; - return this; - } - - public ConfigPusherConfigurationBuilder withNetconfPushConfigDelayMs(long netconfPushConfigDelayMs) { - this.netconfPushConfigDelayMs = netconfPushConfigDelayMs; - return this; - } - - public ConfigPusherConfiguration build() { - ConfigPusherConfiguration configPusherConfiguration = new ConfigPusherConfiguration(netconfAddress, - netconfCapabilitiesWaitTimeoutMs, netconfSendMessageDelayMs, netconfSendMessageMaxAttempts, - connectionAttemptDelayMs, connectionAttemptTimeoutMs, eventLoopGroup, netconfPushConfigAttempts, - netconfPushConfigDelayMs); - return configPusherConfiguration; - } -} diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/Util.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/Util.java deleted file mode 100644 index 322a9b753b..0000000000 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/Util.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.persist.impl; - -import org.opendaylight.controller.netconf.client.NetconfClient; -import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Set; - -public final class Util { - private static final Logger logger = LoggerFactory.getLogger(Util.class); - - - public static boolean isSubset(NetconfClient netconfClient, Set expectedCaps) { - return isSubset(netconfClient.getCapabilities(), expectedCaps); - - } - - private static boolean isSubset(Set currentCapabilities, Set expectedCaps) { - for (String exCap : expectedCaps) { - if (currentCapabilities.contains(exCap) == false) - return false; - } - return true; - } - - public static void closeClientAndDispatcher(NetconfClient client) { - NetconfClientDispatcher dispatcher = client.getNetconfClientDispatcher(); - Exception fromClient = null; - try { - client.close(); - } catch (Exception e) { - fromClient = e; - } finally { - try { - dispatcher.close(); - } catch (Exception e) { - if (fromClient != null) { - e.addSuppressed(fromClient); - } - throw new RuntimeException("Error closing temporary client ", e); - } - } - } -} diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java index 1246c78fbe..76afe8eb39 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java @@ -9,148 +9,139 @@ package org.opendaylight.controller.netconf.persist.impl.osgi; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Optional; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; +import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; +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.ConfigPusherConfiguration; -import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfigurationBuilder; import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator; -import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.Filter; +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; import javax.management.MBeanServer; import java.lang.management.ManagementFactory; -import java.net.InetSocketAddress; -import java.util.concurrent.ThreadFactory; -import java.util.regex.Pattern; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; public class ConfigPersisterActivator implements BundleActivator { private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterActivator.class); - public static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex"; - - public static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS = "maxWaitForCapabilitiesMillis"; + 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 CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY = "conflictingVersionTimeoutMillis"; + private static final long CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT = TimeUnit.SECONDS.toMillis(30); public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister"; public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX = "storageAdapterClass"; - public static final String DEFAULT_IGNORED_REGEX = "^urn:ietf:params:xml:ns:netconf:base:1.0"; - private final MBeanServer platformMBeanServer; + private static final MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); - private final Optional initialConfigForPusher; - private volatile ConfigPersisterNotificationHandler jmxNotificationHandler; - private Thread initializationThread; - private ThreadFactory initializationThreadFactory; - private EventLoopGroup nettyThreadGroup; - private PersisterAggregator persisterAggregator; + private List autoCloseables; - public ConfigPersisterActivator() { - this(new ThreadFactory() { - @Override - public Thread newThread(Runnable initializationRunnable) { - return new Thread(initializationRunnable, "ConfigPersister-registrator"); - } - }, ManagementFactory.getPlatformMBeanServer(), null); - } - - @VisibleForTesting - protected ConfigPersisterActivator(ThreadFactory threadFactory, MBeanServer mBeanServer, - ConfigPusherConfiguration initialConfigForPusher) { - this.initializationThreadFactory = threadFactory; - this.platformMBeanServer = mBeanServer; - this.initialConfigForPusher = Optional.fromNullable(initialConfigForPusher); - } @Override public void start(final BundleContext context) throws Exception { logger.debug("ConfigPersister starting"); - + autoCloseables = new ArrayList<>(); PropertiesProviderBaseImpl propertiesProvider = new PropertiesProviderBaseImpl(context); - final Pattern ignoredMissingCapabilityRegex = getIgnoredCapabilitiesProperty(propertiesProvider); - persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider); + final PersisterAggregator persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider); + autoCloseables.add(persisterAggregator); + final long maxWaitForCapabilitiesMillis = getMaxWaitForCapabilitiesMillis(propertiesProvider); + final List configs = persisterAggregator.loadLastConfigs(); + final long conflictingVersionTimeoutMillis = getConflictingVersionTimeoutMillis(propertiesProvider); + logger.trace("Following configs will be pushed: {}", configs); + ServiceTrackerCustomizer configNetconfCustomizer = new ServiceTrackerCustomizer() { + @Override + public NetconfOperationServiceFactory addingService(ServiceReference 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; + } - final ConfigPusher configPusher = new ConfigPusher(getConfigurationForPusher(context, propertiesProvider)); + @Override + public void modifiedService(ServiceReference reference, NetconfOperationServiceFactory service) { + } - // offload initialization to another thread in order to stop blocking activator - Runnable initializationRunnable = new Runnable() { @Override - public void run() { - try { - configPusher.pushConfigs(persisterAggregator.loadLastConfigs()); - jmxNotificationHandler = new ConfigPersisterNotificationHandler(platformMBeanServer, persisterAggregator, - ignoredMissingCapabilityRegex); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.error("Interrupted while waiting for netconf connection"); - // uncaught exception handler will deal with this failure - throw new RuntimeException("Interrupted while waiting for netconf connection", e); - } - logger.info("Configuration Persister initialization completed."); + public void removedService(ServiceReference reference, NetconfOperationServiceFactory service) { } }; - initializationThread = initializationThreadFactory.newThread(initializationRunnable); - initializationThread.start(); - } - - private Pattern getIgnoredCapabilitiesProperty(PropertiesProviderBaseImpl propertiesProvider) { - String regexProperty = propertiesProvider.getProperty(IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX); - String regex; - if (regexProperty != null) { - regex = regexProperty; - } else { - regex = DEFAULT_IGNORED_REGEX; - } - return Pattern.compile(regex); - } + Filter filter = context.createFilter(getFilterString()); - private Optional getMaxWaitForCapabilitiesProperty(PropertiesProviderBaseImpl propertiesProvider) { - String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS); - return Optional.fromNullable(timeoutProperty == null ? null : Long.valueOf(timeoutProperty)); + ServiceTracker tracker = + new ServiceTracker<>(context, filter, configNetconfCustomizer); + tracker.open(); } - private ConfigPusherConfiguration getConfigurationForPusher(BundleContext context, - PropertiesProviderBaseImpl propertiesProvider) { - - // If configuration was injected via constructor, use it - if(initialConfigForPusher.isPresent()) - return initialConfigForPusher.get(); - - Optional maxWaitForCapabilitiesMillis = getMaxWaitForCapabilitiesProperty(propertiesProvider); - final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context, - "Netconf is not configured, persister is not operational", true); - - nettyThreadGroup = new NioEventLoopGroup(); - ConfigPusherConfigurationBuilder configPusherConfigurationBuilder = ConfigPusherConfigurationBuilder.aConfigPusherConfiguration(); + @VisibleForTesting + public static String getFilterString() { + return "(&" + + "(" + Constants.OBJECTCLASS + "=" + NetconfOperationServiceFactory.class.getName() + ")" + + "(name" + "=" + "config-netconf-connector" + ")" + + ")"; + } - if(maxWaitForCapabilitiesMillis.isPresent()) - configPusherConfigurationBuilder.withNetconfCapabilitiesWaitTimeoutMs(maxWaitForCapabilitiesMillis.get()); + 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); + } - return configPusherConfigurationBuilder - .withEventLoopGroup(nettyThreadGroup) - .withNetconfAddress(address) - .build(); + 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); } @Override - public void stop(BundleContext context) throws Exception { - initializationThread.interrupt(); - if (jmxNotificationHandler != null) { - jmxNotificationHandler.close(); + public synchronized void stop(BundleContext context) 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; } - if(nettyThreadGroup!=null) - nettyThreadGroup.shutdownGracefully(); - persisterAggregator.close(); } } diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolderTest.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolderTest.java index d91712f347..7e9d80abc0 100644 --- a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolderTest.java +++ b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolderTest.java @@ -10,44 +10,30 @@ package org.opendaylight.controller.netconf.persist.impl; import com.google.common.collect.Sets; import org.apache.commons.io.IOUtils; import org.junit.Test; -import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.w3c.dom.Element; import java.io.IOException; -import java.util.Collections; import java.util.HashSet; import java.util.Set; -import java.util.regex.Pattern; import static org.junit.Assert.assertEquals; public class CapabilityStrippingConfigSnapshotHolderTest { @Test - public void testCapabilityStripping() throws Exception { + public void testCapabilityStripping() throws Exception { Set allCapabilities = readLines("/capabilities-all.txt"); Set expectedCapabilities = readLines("/capabilities-stripped.txt"); String snapshotAsString = readToString("/snapshot.xml"); Element element = XmlUtil.readXmlToElement(snapshotAsString); - { - CapabilityStrippingConfigSnapshotHolder tested = new CapabilityStrippingConfigSnapshotHolder( - element, allCapabilities, Pattern.compile( - ConfigPersisterActivator.DEFAULT_IGNORED_REGEX - )); - assertEquals(expectedCapabilities, tested.getCapabilities()); - assertEquals(Collections.emptySet(), tested.getMissingNamespaces()); - } - { - // test regex - CapabilityStrippingConfigSnapshotHolder tested = new CapabilityStrippingConfigSnapshotHolder( - element, allCapabilities, Pattern.compile( - "^bar" - )); - assertEquals(expectedCapabilities, tested.getCapabilities()); - assertEquals(Sets.newHashSet(ConfigPersisterActivator.DEFAULT_IGNORED_REGEX.substring(1)), - tested.getMissingNamespaces()); - } + CapabilityStrippingConfigSnapshotHolder tested = new CapabilityStrippingConfigSnapshotHolder( + element, allCapabilities); + assertEquals(expectedCapabilities, tested.getCapabilities()); + + Set obsoleteCapabilities = Sets.difference(allCapabilities, expectedCapabilities); + + assertEquals(obsoleteCapabilities, tested.getObsoleteCapabilities()); } private Set readLines(String fileName) throws IOException { diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java index 230c74725d..b722496142 100644 --- a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java +++ b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java @@ -7,267 +7,138 @@ */ package org.opendaylight.controller.netconf.persist.impl.osgi; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - -import java.lang.management.ManagementFactory; -import java.net.InetSocketAddress; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeoutException; - -import javax.management.MBeanServer; - +import com.google.common.collect.Sets; import org.junit.After; -import org.junit.AfterClass; -import org.junit.BeforeClass; +import org.junit.Before; import org.junit.Test; -import org.junit.matchers.JUnitMatchers; import org.opendaylight.controller.config.api.ConflictingVersionException; -import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer; -import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfiguration; -import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfigurationBuilder; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.mapping.api.Capability; +import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; +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.persist.impl.osgi.MockedBundleContext.DummyAdapterWithInitialSnapshot; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; -import com.google.common.collect.Lists; -import io.netty.channel.nio.NioEventLoopGroup; +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; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; public class ConfigPersisterTest { + private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterTest.class); private MockedBundleContext ctx; private ConfigPersisterActivator configPersisterActivator; private static final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); + private TestingExceptionHandler handler; - private static final String NETCONF_ADDRESS = "localhost"; - private static final String NETCONF_PORT = "18383"; - private static NioEventLoopGroup eventLoopGroup; - private void setUpContextAndStartPersister(Thread.UncaughtExceptionHandler exHandler, String requiredCapability, ConfigPusherConfiguration configuration) - throws Exception { - MockedBundleContext.DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability; - ctx = new MockedBundleContext(NETCONF_ADDRESS, NETCONF_PORT); - configPersisterActivator = new ConfigPersisterActivator(getThreadFactory(exHandler), mBeanServer, - configuration); + private void setUpContextAndStartPersister(String requiredCapability) throws Exception { + DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability; + ctx = new MockedBundleContext(1000, 1000); + configPersisterActivator = new ConfigPersisterActivator(); configPersisterActivator.start(ctx.getBundleContext()); } - @BeforeClass - public static void setUp() throws Exception { - eventLoopGroup = new NioEventLoopGroup(); + @Before + public void setUp() { + handler = new TestingExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(handler); } @After public void tearDown() throws Exception { + Thread.setDefaultUncaughtExceptionHandler(null); configPersisterActivator.stop(ctx.getBundleContext()); } - @AfterClass - public static void closeNettyGroup() throws Exception { - eventLoopGroup.shutdownGracefully(); - } - - @Test - public void testPersisterNetconfNotStarting() throws Exception { - final TestingExceptionHandler handler = new TestingExceptionHandler(); - - setUpContextAndStartPersister(handler, "cap2", getConfiguration(100, 100).build()); - - waitTestToFinish(2000); - - handler.assertException("connect to netconf endpoint", RuntimeException.class, - "Could not connect to netconf server"); - } - @Test public void testPersisterNotAllCapabilitiesProvided() throws Exception { - final TestingExceptionHandler handler = new TestingExceptionHandler(); - ConfigPusherConfiguration cfg = getConfiguration(500, 1000) - .withNetconfCapabilitiesWaitTimeoutMs(1000).build(); - - setUpContextAndStartPersister(handler, "required-cap", cfg); + setUpContextAndStartPersister("required-cap"); + Thread.sleep(2000); + handler.assertException(IllegalStateException.class, "Max wait for capabilities reached.Not enough capabilities " + + "for . Expected but not found: [required-cap]"); - try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) { - - waitTestToFinish(2500); - - handler.assertException("retrieve required capabilities from netconf endpoint", RuntimeException.class, - "Expected but not found:[required-cap]"); - } } @Test - public void testPersisterNoResponseFromNetconfAfterEdit() throws Exception { - final TestingExceptionHandler handler = new TestingExceptionHandler(); - ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt(); - - setUpContextAndStartPersister(handler, "cap1", cfg); - - try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) { - - waitTestToFinish(3000); - - handler.assertException("receive response from netconf endpoint", IllegalStateException.class, - "Unable to load", TimeoutException.class, - null, 3); - - assertEquals(1 + 2, endpoint.getReceivedMessages().size()); - assertHelloMessage(endpoint.getReceivedMessages().get(1)); - assertEditMessage(endpoint.getReceivedMessages().get(2)); - } + public void testPersisterSuccessfulPush() throws Exception { + setUpContextAndStartPersister("cap1"); + NetconfOperationService service = getWorkingService(getOKDocument()); + doReturn(service).when(ctx.serviceFactory).createService(anyString()); + Thread.sleep(2000); + assertCannotRegisterAsJMXListener_pushWasSuccessful(); } - private ConfigPusherConfiguration getConfigurationWithOnePushAttempt() { - return getConfiguration(500, 1000) - .withNetconfCapabilitiesWaitTimeoutMs(1000) - .withNetconfPushConfigAttempts(1) - .withNetconfPushConfigDelayMs(100) - .withNetconfSendMessageMaxAttempts(3) - .withNetconfSendMessageDelayMs(500).build(); + // this means pushing of config was successful + public void assertCannotRegisterAsJMXListener_pushWasSuccessful() { + handler.assertException(RuntimeException.class, "Cannot register as JMX listener to netconf"); } - @Test - public void testPersisterSuccessfulPush() throws Exception { - final TestingExceptionHandler handler = new TestingExceptionHandler(); - ConfigPusherConfiguration cfg = getConfigurationForSuccess(); - - setUpContextAndStartPersister(handler, "cap1", cfg); - - try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage, - MockNetconfEndpoint.okMessage)) { + public NetconfOperationService getWorkingService(Document document) throws SAXException, IOException, NetconfDocumentedException { + NetconfOperationService service = mock(NetconfOperationService.class); + Capability capability = mock(Capability.class); + doReturn(Sets.newHashSet(capability)).when(service).getCapabilities(); + doReturn("cap1").when(capability).getCapabilityUri(); - waitTestToFinish(4000); - handler.assertException("register as JMX listener", RuntimeException.class, - "Cannot register as JMX listener to netconf"); - - assertEquals(1 + 3, endpoint.getReceivedMessages().size()); - assertCommitMessage(endpoint.getReceivedMessages().get(3)); - } + NetconfOperation mockedOperation = mock(NetconfOperation.class); + doReturn(Sets.newHashSet(mockedOperation)).when(service).getNetconfOperations(); + doReturn(HandlingPriority.getHandlingPriority(1)).when(mockedOperation).canHandle(any(Document.class)); + doReturn(document).when(mockedOperation).handle(any(Document.class), any(NetconfOperationChainedExecution.class)); + doNothing().when(service).close(); + return service; } - private ConfigPusherConfiguration getConfigurationForSuccess() { - return getConfiguration(500, 1000) - .withNetconfCapabilitiesWaitTimeoutMs(1000) - .withNetconfPushConfigAttempts(3) - .withNetconfPushConfigDelayMs(100) - .withNetconfSendMessageMaxAttempts(3) - .withNetconfSendMessageDelayMs(500).build(); + private Document getOKDocument() throws SAXException, IOException { + return XmlUtil.readXmlToDocument( + "\n" + + "\n" + + "" + ); } + @Test public void testPersisterConflictingVersionException() throws Exception { - final TestingExceptionHandler handler = new TestingExceptionHandler(); - ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt(); - - setUpContextAndStartPersister(handler, "cap1", cfg); - - try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage, - MockNetconfEndpoint.conflictingVersionErrorMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier();) { - - Thread.sleep(4000); - - handler.assertException("register as JMX listener", IllegalStateException.class, - "Maximum attempt count has been reached for pushing", ConflictingVersionException.class, "Optimistic lock failed", 1); - - assertEquals(1 + 3, endpoint.getReceivedMessages().size()); - assertCommitMessage(endpoint.getReceivedMessages().get(3)); - } + setUpContextAndStartPersister("cap1"); + NetconfOperationService service = getWorkingService(getConflictVersionDocument()); + doReturn(service).when(ctx.serviceFactory).createService(anyString()); + Thread.sleep(2000); + handler.assertException(IllegalStateException.class, "Max wait for conflicting version stabilization timeout"); } - @Test - public void testPersisterConflictingVersionExceptionThenSuccess() throws Exception { - final TestingExceptionHandler handler = new TestingExceptionHandler(); - ConfigPusherConfiguration cfg = getConfigurationForSuccess(); - - setUpContextAndStartPersister(handler, "cap1", cfg); - - MockNetconfEndpoint.MessageSequence conflictingMessageSequence = new MockNetconfEndpoint.MessageSequence( - MockNetconfEndpoint.okMessage, MockNetconfEndpoint.conflictingVersionErrorMessage); - MockNetconfEndpoint.MessageSequence okMessageSequence = new MockNetconfEndpoint.MessageSequence( - MockNetconfEndpoint.okMessage, MockNetconfEndpoint.okMessage); - - try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", - Lists.newArrayList(conflictingMessageSequence, okMessageSequence)); - DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) { - - Thread.sleep(4000); - - handler.assertNoException(); - - assertEquals(1 + 3/*Hello + Edit + Commit*/ + 3/*Hello + Edit + Commit*/, endpoint.getReceivedMessages().size()); - assertCommitMessage(endpoint.getReceivedMessages().get(6)); - } + private Document getConflictVersionDocument() throws SAXException, IOException { + return XmlUtil.readXmlToDocument( + "\n" + + "" + + ConflictingVersionException.class.getCanonicalName() + + "\n" + + "" + ); } @Test - public void testPersisterSuccessfulPushAndSuccessfulJMXRegistration() throws Exception { - final TestingExceptionHandler handler = new TestingExceptionHandler(); - ConfigPusherConfiguration cfg = getConfigurationForSuccess(); - - setUpContextAndStartPersister(handler, "cap1", cfg); - - try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage, - MockNetconfEndpoint.okMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) { - - Thread.sleep(2000); - - handler.assertNoException(); - - assertEquals(1 + 3, endpoint.getReceivedMessages().size()); - } - } - - private ConfigPusherConfigurationBuilder getConfiguration(int connectionAttemptDelayMs, int connectionAttemptTimeoutMs) { - return ConfigPusherConfigurationBuilder.aConfigPusherConfiguration() - .withEventLoopGroup(eventLoopGroup) - .withConnectionAttemptDelayMs(connectionAttemptDelayMs) - .withConnectionAttemptTimeoutMs(connectionAttemptTimeoutMs) - .withNetconfCapabilitiesWaitTimeoutMs(44) - .withNetconfAddress(new InetSocketAddress(NETCONF_ADDRESS, Integer.valueOf(NETCONF_PORT))); + public void testSuccessConflictingVersionException() throws Exception { + setUpContextAndStartPersister("cap1"); + doReturn(getWorkingService(getConflictVersionDocument())).when(ctx.serviceFactory).createService(anyString()); + Thread.sleep(500); + // working service: + logger.info("Switching to working service **"); + doReturn(getWorkingService(getOKDocument())).when(ctx.serviceFactory).createService(anyString()); + Thread.sleep(1000); + assertCannotRegisterAsJMXListener_pushWasSuccessful(); } - private void waitTestToFinish(int i) throws InterruptedException { - Thread.sleep(i); - } - - - private DefaultCommitNotificationProducer startJMXCommitNotifier() { - return new DefaultCommitNotificationProducer(mBeanServer); - } - - private void assertEditMessage(String netconfMessage) { - assertThat(netconfMessage, - JUnitMatchers.containsString(MockedBundleContext.DummyAdapterWithInitialSnapshot.CONFIG_SNAPSHOT)); - } - - private void assertCommitMessage(String netconfMessage) { - assertThat(netconfMessage, JUnitMatchers.containsString("")); - assertThat(netconfMessage, JUnitMatchers.containsString("")); - } - - private MockNetconfEndpoint startMockNetconfEndpoint(String capability, List messageSequences) { - // Add first empty sequence for testing connection created by config persister at startup - messageSequences.add(0, new MockNetconfEndpoint.MessageSequence(Collections.emptyList())); - return new MockNetconfEndpoint(capability, NETCONF_PORT, messageSequences); - } - - private MockNetconfEndpoint startMockNetconfEndpoint(String capability, String... messages) { - return startMockNetconfEndpoint(capability, Lists.newArrayList(new MockNetconfEndpoint.MessageSequence(messages))); - } - - public ThreadFactory getThreadFactory(final Thread.UncaughtExceptionHandler exHandler) { - return new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, "config-persister-testing-activator"); - thread.setUncaughtExceptionHandler(exHandler); - return thread; - } - }; - } } diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java deleted file mode 100644 index 913db280b5..0000000000 --- a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * 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.persist.impl.osgi; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketTimeoutException; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.opendaylight.controller.netconf.util.test.XmlFileLoader; -import org.opendaylight.controller.netconf.util.xml.XmlUtil; - -import com.google.common.collect.Lists; - -class MockNetconfEndpoint implements AutoCloseable { - - public static final int READ_SOCKET_TIMEOUT = 3000; - - public static final String MSG_SEPARATOR = "]]>]]>\n"; - - private final AtomicBoolean stopped = new AtomicBoolean(false); - private List receivedMessages = Lists.newCopyOnWriteArrayList(); - private Thread innerThread; - - MockNetconfEndpoint(String capability, String netconfPort, List messageSequence) { - helloMessage = helloMessage.replace("capability_place_holder", capability); - start(netconfPort, messageSequence); - } - - private String helloMessage = "\n" + - "\n" + - "capability_place_holder\n" + - "\n" + - "1\n" + - "\n" + - MSG_SEPARATOR; - - public static String conflictingVersionErrorMessage; - static { - try { - conflictingVersionErrorMessage = XmlUtil.toString(XmlFileLoader - .xmlFileToDocument("netconfMessages/conflictingversion/conflictingVersionResponse.xml")) + MSG_SEPARATOR; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public static String okMessage = "\n" + - "\n" + - "" + - MSG_SEPARATOR ; - - private void start(final String port, final List messagesToSend) { - innerThread = new Thread(new Runnable() { - @Override - public void run() { - int clientCounter = 0; - - while (stopped.get() == false) { - try (ServerSocket s = new ServerSocket(Integer.valueOf(port))) { - s.setSoTimeout(READ_SOCKET_TIMEOUT); - - Socket clientSocket = s.accept(); - clientCounter++; - clientSocket.setSoTimeout(READ_SOCKET_TIMEOUT); - - PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); - BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); - - // Negotiate - sendMessage(out, helloMessage); - receiveMessage(in); - - // Accept next message (edit-config) - receiveMessage(in); - - for (String message : getMessageSequenceForClient(messagesToSend, clientCounter)) { - sendMessage(out, message); - receiveMessage(in); - } - } catch (SocketTimeoutException e) { - // No more activity on netconf endpoint, close - return; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } - - private Iterable getMessageSequenceForClient(List messagesToSend, - int clientCounter) { - if (messagesToSend.size() <= clientCounter) { - return messagesToSend.get(messagesToSend.size() - 1).getMessages(); - } else { - return messagesToSend.get(clientCounter - 1).getMessages(); - } - } - - private void receiveMessage(BufferedReader in) throws Exception { - String message = readMessage(in); - if(message == null || message.equals("")) - return; - receivedMessages.add(message); - } - - private String readMessage(BufferedReader in) throws IOException { - int c; - StringBuilder b = new StringBuilder(); - - while((c = in.read()) != -1) { - b.append((char)c); - if(b.toString().endsWith("]]>]]>")) - break; - } - - return b.toString(); - } - - private void sendMessage(PrintWriter out, String message) throws InterruptedException { - out.print(message); - out.flush(); - } - - }); - innerThread.setName("Mocked-netconf-endpoint-inner-thread"); - innerThread.start(); - } - - public List getReceivedMessages() { - return receivedMessages; - } - - public void close() throws IOException, InterruptedException { - stopped.set(true); - innerThread.join(); - } - - static class MessageSequence { - private List messages; - - MessageSequence(List messages) { - this.messages = messages; - } - - MessageSequence(String... messages) { - this(Lists.newArrayList(messages)); - } - - public Collection getMessages() { - return messages; - } - } -} diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java index 97cf7ecfe7..8bc787bdef 100644 --- a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java +++ b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java @@ -14,41 +14,71 @@ import org.mockito.MockitoAnnotations; 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.NetconfOperationService; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory; import org.opendaylight.controller.netconf.persist.impl.DummyAdapter; +import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import org.osgi.framework.Filter; +import org.osgi.framework.ServiceListener; +import org.osgi.framework.ServiceReference; import java.io.IOException; +import java.util.Collections; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; final class MockedBundleContext { - @Mock private BundleContext context; + @Mock + private Filter filter; + @Mock + private ServiceReference serviceReference; + @Mock + private Bundle bundle; + @Mock + NetconfOperationServiceFactory serviceFactory; + @Mock + private NetconfOperationService service; - MockedBundleContext(String netconfAddress, String netconfPort) { + MockedBundleContext(long maxWaitForCapabilitiesMillis, long conflictingVersionTimeoutMillis) throws Exception { MockitoAnnotations.initMocks(this); - initContext(netconfAddress, netconfPort); + 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)); + ServiceReference[] toBeReturned = {serviceReference}; + doReturn(toBeReturned).when(context).getServiceReferences((String) null, filterString); + doReturn(bundle).when(serviceReference).getBundle(); + doReturn(context).when(bundle).getBundleContext(); + doReturn("").when(serviceReference).toString(); + doReturn(serviceFactory).when(context).getService(any(ServiceReference.class)); + doReturn(service).when(serviceFactory).createService(anyString()); + doReturn(Collections.emptySet()).when(service).getCapabilities(); + doNothing().when(service).close(); } public BundleContext getBundleContext() { return context; } - private void initContext(String netconfAddress, String netconfPort) { - initProp(context, ConfigPersisterActivator.IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX, null); - - initPropNoPrefix(context, "netconf.tcp.client.address", netconfAddress); - initPropNoPrefix(context, "netconf.tcp.client.port", netconfPort); - + private void initContext(long maxWaitForCapabilitiesMillis, long conflictingVersionTimeoutMillis) { initProp(context, "active", "1"); initProp(context, "1." + ConfigPersisterActivator.STORAGE_ADAPTER_CLASS_PROP_SUFFIX, DummyAdapterWithInitialSnapshot.class.getName()); initProp(context, "1." + "readonly", "false"); initProp(context, "1." + ".properties.fileStorage", "target/configuration-persister-test/initial/"); - + initProp(context, ConfigPersisterActivator.MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY, String.valueOf(maxWaitForCapabilitiesMillis)); + initProp(context, ConfigPersisterActivator.CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY, String.valueOf(conflictingVersionTimeoutMillis)); } private void initProp(BundleContext context, String key, String value) { @@ -66,7 +96,7 @@ final class MockedBundleContext { @Override public List loadLastConfigs() throws IOException { - return Lists.newArrayList(getConfigSnapshopt()); + return Lists.newArrayList(getConfigSnapshot()); } @Override @@ -74,7 +104,7 @@ final class MockedBundleContext { return this; } - public ConfigSnapshotHolder getConfigSnapshopt() { + public ConfigSnapshotHolder getConfigSnapshot() { return new ConfigSnapshotHolder() { @Override public String getConfigSnapshot() { diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java index d42c15b834..6fb231d847 100644 --- a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java +++ b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java @@ -24,6 +24,10 @@ final class TestingExceptionHandler implements Thread.UncaughtExceptionHandler { this.t = e; } + public void assertException(Class exType, String exMessageToContain) { + assertException(exMessageToContain, exType, exMessageToContain); + } + public void assertException(String failMessageSuffix, Class exType, String exMessageToContain) { if(t == null) { fail("Should fail to " + failMessageSuffix); diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java index 8d532d45e8..a358514453 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java @@ -7,12 +7,9 @@ */ package org.opendaylight.controller.netconf.impl.osgi; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfOperationRouter; import org.opendaylight.controller.netconf.api.NetconfSession; @@ -33,9 +30,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; -import com.google.common.base.Preconditions; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; public class NetconfOperationRouterImpl implements NetconfOperationRouter { @@ -186,18 +185,6 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter { return sortedPriority; } - public static final NetconfOperationChainedExecution EXECUTION_TERMINATION_POINT = new NetconfOperationChainedExecution() { - @Override - public boolean isExecutionTermination() { - return true; - } - - @Override - public Document execute(Document requestMessage) throws NetconfDocumentedException { - throw new IllegalStateException("This execution represents the termination point in operation execution and cannot be executed itself"); - } - }; - private static class NetconfOperationExecution implements NetconfOperationChainedExecution { private final NetconfOperation netconfOperation; private NetconfOperationChainedExecution subsequentExecution; diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceSnapshot.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceSnapshot.java index cb4f53257e..5c08505091 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceSnapshot.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceSnapshot.java @@ -8,15 +8,15 @@ package org.opendaylight.controller.netconf.impl.osgi; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - 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 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); @@ -27,7 +27,7 @@ public class NetconfOperationServiceSnapshot implements AutoCloseable { Set services = new HashSet<>(); netconfSessionIdForReporting = getNetconfSessionIdForReporting(sessionId); for (NetconfOperationServiceFactory factory : factories) { - services.add(factory.createService(sessionId, netconfSessionIdForReporting)); + services.add(factory.createService(netconfSessionIdForReporting)); } this.services = Collections.unmodifiableSet(services); } diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java index 07da7f990a..c1a7b1478b 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java @@ -111,7 +111,7 @@ public class ConcurrentClientsTest { private NetconfOperationServiceFactory mockOpF() { return new NetconfOperationServiceFactory() { @Override - public NetconfOperationService createService(long netconfSessionId, String netconfSessionIdForReporting) { + public NetconfOperationService createService(String netconfSessionIdForReporting) { return new NetconfOperationService() { @Override public Set getCapabilities() { diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java index 19007cd037..997cae0f7c 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java @@ -22,13 +22,13 @@ import org.opendaylight.controller.config.manager.impl.factoriesresolver.Hardcod import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; import org.opendaylight.controller.config.persist.api.Persister; 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.jmx.CommitJMXNotification; import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession; import org.opendaylight.controller.netconf.client.NetconfClient; 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; @@ -54,7 +54,6 @@ import java.net.InetSocketAddress; import java.util.Collection; import java.util.List; import java.util.Set; -import java.util.regex.Pattern; import static junit.framework.Assert.assertEquals; import static org.mockito.Matchers.any; @@ -124,7 +123,7 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest { try (NetconfClient persisterClient = new NetconfClient("persister", tcpAddress, 4000, clientDispatcher)) { try (ConfigPersisterNotificationHandler configPersisterNotificationHandler = new ConfigPersisterNotificationHandler( - platformMBeanServer, mockedAggregator, Pattern.compile(""))) { + platformMBeanServer, mockedAggregator)) { try (NetconfClient netconfClient = new NetconfClient("client", tcpAddress, 4000, clientDispatcher)) { diff --git a/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/HandlingPriority.java b/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/HandlingPriority.java index 1236138e6c..05122be4d2 100644 --- a/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/HandlingPriority.java +++ b/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/HandlingPriority.java @@ -45,6 +45,10 @@ public class HandlingPriority implements Comparable { return getHandlingPriority(priority + priorityIncrease); } + public boolean isCannotHandle() { + return this.equals(CANNOT_HANDLE); + } + @Override public int compareTo(HandlingPriority o) { if (this == o) diff --git a/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationChainedExecution.java b/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationChainedExecution.java index 2298153017..4013d623bd 100644 --- a/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationChainedExecution.java +++ b/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationChainedExecution.java @@ -27,4 +27,18 @@ public interface NetconfOperationChainedExecution { * Do not execute if this is termination point */ Document execute(Document requestMessage) throws NetconfDocumentedException; + + public static final NetconfOperationChainedExecution EXECUTION_TERMINATION_POINT = new NetconfOperationChainedExecution() { + @Override + public boolean isExecutionTermination() { + return true; + } + + @Override + public Document execute(Document requestMessage) throws NetconfDocumentedException { + throw new IllegalStateException("This execution represents the termination point in operation execution and cannot be executed itself"); + } + }; + + } diff --git a/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationServiceFactory.java b/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationServiceFactory.java index 46b9cd22e0..81401f26ee 100644 --- a/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationServiceFactory.java +++ b/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationServiceFactory.java @@ -15,6 +15,6 @@ package org.opendaylight.controller.netconf.mapping.api; */ public interface NetconfOperationServiceFactory { - NetconfOperationService createService(long netconfSessionId, String netconfSessionIdForReporting); + NetconfOperationService createService(String netconfSessionIdForReporting); } diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivator.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivator.java index 1143231442..de04484d13 100644 --- a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivator.java +++ b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivator.java @@ -46,7 +46,7 @@ public class NetconfMonitoringActivator implements BundleActivator { } @Override - public NetconfOperationService createService(long netconfSessionId, String netconfSessionIdForReporting) { + public NetconfOperationService createService(String netconfSessionIdForReporting) { return operationService; } } diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/NetconfUtil.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/NetconfUtil.java index 796ab91a50..b0884ca2fb 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/NetconfUtil.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/NetconfUtil.java @@ -56,13 +56,17 @@ public final class NetconfUtil { return (doc == null) ? null : new NetconfMessage(doc); } - public static void checkIsMessageOk(NetconfMessage responseMessage) throws ConflictingVersionException { - XmlElement element = XmlElement.fromDomDocument(responseMessage.getDocument()); + public static Document checkIsMessageOk(NetconfMessage responseMessage) throws ConflictingVersionException { + return checkIsMessageOk(responseMessage.getDocument()); + } + + public static Document checkIsMessageOk(Document response) throws ConflictingVersionException { + XmlElement element = XmlElement.fromDomDocument(response); Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY)); element = element.getOnlyChildElement(); if (element.getName().equals(XmlNetconfConstants.OK)) { - return; + return response; } if (element.getName().equals(XmlNetconfConstants.RPC_ERROR)) { @@ -74,11 +78,11 @@ public final class NetconfUtil { throw new ConflictingVersionException(error); } throw new IllegalStateException("Can not load last configuration, operation failed: " - + XmlUtil.toString(responseMessage.getDocument())); + + XmlUtil.toString(response)); } logger.warn("Can not load last configuration. Operation failed."); throw new IllegalStateException("Can not load last configuration. Operation failed: " - + XmlUtil.toString(responseMessage.getDocument())); + + XmlUtil.toString(response)); } }