From: Ed Warnicke Date: Fri, 15 Aug 2014 15:24:43 +0000 (+0000) Subject: Merge "Revert "BUG-1425: Integrated new Binding to Normalized Node codec for write... X-Git-Tag: release/helium~284 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=596901e767e8c988dbb88d4efb3f64c0d6676b54;hp=be2b35105f8e10ada7d73f4523a5a931c57323b3;p=controller.git Merge "Revert "BUG-1425: Integrated new Binding to Normalized Node codec for write path"" --- diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java index d60e608617..abb9f1ae9b 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java @@ -35,7 +35,6 @@ public class ObjectNameUtil { public static final String SERVICE_QNAME_KEY = "serviceQName"; public static final String INSTANCE_NAME_KEY = "instanceName"; public static final String TYPE_KEY = ConfigRegistryConstants.TYPE_KEY; - public static final String TYPE_CONFIG_REGISTRY = ConfigRegistryConstants.TYPE_CONFIG_REGISTRY; public static final String TYPE_CONFIG_TRANSACTION = "ConfigTransaction"; public static final String TYPE_MODULE = "Module"; public static final String TYPE_SERVICE_REFERENCE = "ServiceReference"; @@ -43,6 +42,7 @@ public class ObjectNameUtil { public static final String TRANSACTION_NAME_KEY = "TransactionName"; public static final String REF_NAME_KEY = "RefName"; private static final String REPLACED_QUOTATION_MARK = "\\?"; + public static final String ON_WILDCARD = "*"; public static ObjectName createON(String on) { try { @@ -304,12 +304,9 @@ public class ObjectNameUtil { public static ObjectName createModulePattern(String moduleName, String instanceName) { - if (moduleName == null) { - moduleName = "*"; - } - if (instanceName == null) { - instanceName = "*"; - } + moduleName = moduleName == null ? ON_WILDCARD : moduleName; + instanceName = instanceName == null ? ON_WILDCARD : instanceName; + // do not return object names containing transaction name ObjectName namePattern = ObjectNameUtil .createON(ObjectNameUtil.ON_DOMAIN + ":" @@ -323,6 +320,10 @@ public class ObjectNameUtil { public static ObjectName createModulePattern(String ifcName, String instanceName, String transactionName) { + ifcName = ifcName == null ? ON_WILDCARD : ifcName; + instanceName = instanceName == null ? ON_WILDCARD : instanceName; + transactionName = transactionName == null ? ON_WILDCARD : transactionName; + return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":type=Module," + ObjectNameUtil.MODULE_FACTORY_NAME_KEY + "=" + ifcName + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "=" @@ -332,6 +333,9 @@ public class ObjectNameUtil { public static ObjectName createRuntimeBeanPattern(String moduleName, String instanceName) { + moduleName = moduleName == null ? ON_WILDCARD : moduleName; + instanceName = instanceName == null ? ON_WILDCARD : instanceName; + return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":" + ObjectNameUtil.TYPE_KEY + "=" + ObjectNameUtil.TYPE_RUNTIME_BEAN + "," diff --git a/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/JmxAttributeValidationExceptionTest.java b/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/JmxAttributeValidationExceptionTest.java new file mode 100644 index 0000000000..7a057bbccb --- /dev/null +++ b/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/JmxAttributeValidationExceptionTest.java @@ -0,0 +1,51 @@ +package org.opendaylight.controller.config.api; + +import static org.junit.Assert.assertEquals; + +import com.google.common.collect.Lists; +import org.junit.Before; +import org.junit.Test; + +public class JmxAttributeValidationExceptionTest { + + private JmxAttribute jmxAttribute = new JmxAttribute("attr1"); + private JmxAttribute jmxAttribute2 = new JmxAttribute("attr2"); + + @Before + public void setUp() throws Exception { + + } + + @Test + public void testGetAttributeNames() throws Exception { + + } + + @Test + public void testCheckNotNull() throws Exception { + try { + JmxAttributeValidationException.checkNotNull(false, "message", jmxAttribute); + } catch (JmxAttributeValidationException e) { + assertJmxEx(e, jmxAttribute.getAttributeName() + " " + "message", jmxAttribute); + } + } + + @Test + public void testWrap() throws Exception { + + } + + @Test + public void testCheckCondition() throws Exception { + try { + JmxAttributeValidationException.checkCondition(false, "message", jmxAttribute); + } catch (JmxAttributeValidationException e) { + assertJmxEx(e, jmxAttribute.getAttributeName() + " " + "message", jmxAttribute); + } + } + + private void assertJmxEx(JmxAttributeValidationException e, String message, JmxAttribute... attrNames) { + assertEquals(message, e.getMessage()); + assertEquals(Lists.newArrayList(attrNames), e.getAttributeNames()); + } +} \ No newline at end of file diff --git a/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/ValidationExceptionTest.java b/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/ValidationExceptionTest.java new file mode 100644 index 0000000000..1809e45860 --- /dev/null +++ b/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/ValidationExceptionTest.java @@ -0,0 +1,54 @@ +package org.opendaylight.controller.config.api; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; +import static org.junit.Assert.assertThat; +import static org.junit.matchers.JUnitMatchers.containsString; + +import com.google.common.collect.Lists; +import java.util.Map; +import org.junit.Test; + +public class ValidationExceptionTest { + + private String instance = "instance"; + private final ModuleIdentifier mi = new ModuleIdentifier("module", instance); + private String instance2 = "instance2"; + private final ModuleIdentifier mi2 = new ModuleIdentifier("module", instance2); + private final String message = "ex message"; + private final Exception e = new IllegalStateException(message); + + @Test + public void testCreateFromCollectedValidationExceptions() throws Exception { + ValidationException single = ValidationException.createForSingleException(mi, e); + ValidationException single2 = ValidationException.createForSingleException(mi2, e); + + ValidationException collected = ValidationException.createFromCollectedValidationExceptions(Lists.newArrayList(single, single2)); + + Map> failedMap = collected.getFailedValidations(); + assertEquals(1, failedMap.size()); + assertTrue(failedMap.containsKey("module")); + + Map failedModule = failedMap.get("module"); + assertEquals(2, failedModule.size()); + assertTrue(failedModule.containsKey(instance)); + assertEquals(message, failedModule.get(instance).getMessage()); + assertEquals(message, failedModule.get(instance2).getMessage()); + assertEquals(failedModule.get(instance), failedModule.get(instance2)); + } + + @Test + public void testCreateFromCollectedValidationExceptionsWithDuplicate() throws Exception { + ValidationException single = ValidationException.createForSingleException(mi, e); + ValidationException single2 = ValidationException.createForSingleException(mi, e); + try { + ValidationException.createFromCollectedValidationExceptions(Lists.newArrayList(single, single2)); + } catch (IllegalArgumentException ex) { + // Duplicate exception + assertThat(ex.getMessage(), containsString("Cannot merge")); + return; + } + fail("Duplicate exception should have failed"); + } +} \ No newline at end of file diff --git a/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtilTest.java b/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtilTest.java new file mode 100644 index 0000000000..d3d8469dfb --- /dev/null +++ b/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtilTest.java @@ -0,0 +1,162 @@ +/* + * 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.config.api.jmx; + +import static junit.framework.Assert.fail; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import com.google.common.base.Throwables; +import com.google.common.collect.Maps; +import java.util.Map; +import javax.management.ObjectName; +import junit.framework.Assert; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.config.api.ModuleIdentifier; + +public class ObjectNameUtilTest { + + private String moduleName; + private String instanceName; + + @Before + public void setUp() throws Exception { + moduleName = "module"; + instanceName = "instance"; + } + + @Test + public void testServiceReferenceName() throws Exception { + String serviceQName = "(namespace?revision=r)qname"; + String refName = "refName"; + String transaction = "transaction"; + + ObjectName serviceReferenceON = ObjectNameUtil.createTransactionServiceON(transaction, serviceQName, refName); + ObjectNameUtil.checkType(serviceReferenceON, ObjectNameUtil.TYPE_SERVICE_REFERENCE); + + assertFalse(serviceReferenceON.isPattern()); + assertEquals(serviceQName, ObjectNameUtil.getServiceQName(serviceReferenceON)); + assertEquals(refName, ObjectNameUtil.getReferenceName(serviceReferenceON)); + assertEquals(transaction, ObjectNameUtil.getTransactionName(serviceReferenceON)); + assertEquals(ObjectNameUtil.createReadOnlyServiceON(serviceQName, refName), ObjectNameUtil.withoutTransactionName(serviceReferenceON)); + + serviceReferenceON = ObjectNameUtil.createReadOnlyServiceON(serviceQName, refName); + assertFalse(serviceReferenceON.isPattern()); + assertEquals(serviceQName, ObjectNameUtil.getServiceQName(serviceReferenceON)); + assertEquals(refName, ObjectNameUtil.getReferenceName(serviceReferenceON)); + assertEquals(null, ObjectNameUtil.getTransactionName(serviceReferenceON)); + } + + @Test + public void testModuleName() throws Exception { + String txName = "transaction"; + + ObjectName on = ObjectNameUtil.createTransactionModuleON(txName, moduleName, instanceName); + + ObjectNameUtil.checkDomain(on); + ObjectNameUtil.checkType(on, ObjectNameUtil.TYPE_MODULE); + + assertFalse(on.isPattern()); + assertEquals(moduleName, ObjectNameUtil.getFactoryName(on)); + assertEquals(instanceName, ObjectNameUtil.getInstanceName(on)); + assertEquals(txName, ObjectNameUtil.getTransactionName(on)); + assertEquals(4, ObjectNameUtil.getAdditionalProperties(on).size()); + + ObjectName withoutTx = ObjectNameUtil.withoutTransactionName(on); + assertEquals(ObjectNameUtil.createReadOnlyModuleON(moduleName, instanceName), withoutTx); + assertEquals(moduleName, ObjectNameUtil.getFactoryName(withoutTx)); + assertEquals(instanceName, ObjectNameUtil.getInstanceName(withoutTx)); + assertEquals(null, ObjectNameUtil.getTransactionName(withoutTx)); + assertEquals(on, ObjectNameUtil.withTransactionName(withoutTx, txName)); + + ObjectName pattern = ObjectNameUtil.createModulePattern(moduleName, null); + assertPattern(withoutTx, pattern); + pattern = ObjectNameUtil.createModulePattern(moduleName, null, txName); + assertPattern(on, pattern); + } + + private void assertPattern(ObjectName test, ObjectName pattern) { + assertTrue(pattern.isPattern()); + assertTrue(pattern.apply(test)); + } + + @Test + public void testRuntimeBeanName() throws Exception { + + Map properties = Maps.newHashMap(); + properties.put("p1", "value"); + properties.put("p2", "value2"); + + ObjectName on = ObjectNameUtil.createRuntimeBeanName(moduleName, instanceName, properties); + + ObjectNameUtil.checkDomain(on); + ObjectNameUtil.checkTypeOneOf(on, ObjectNameUtil.TYPE_RUNTIME_BEAN); + + assertFalse(on.isPattern()); + assertEquals(moduleName, ObjectNameUtil.getFactoryName(on)); + assertEquals(instanceName, ObjectNameUtil.getInstanceName(on)); + assertEquals(2, ObjectNameUtil.getAdditionalPropertiesOfRuntimeBeanName(on).size()); + assertTrue(ObjectNameUtil.getAdditionalPropertiesOfRuntimeBeanName(on).containsKey("p1")); + assertEquals("value", ObjectNameUtil.getAdditionalPropertiesOfRuntimeBeanName(on).get("p1")); + assertTrue(ObjectNameUtil.getAdditionalProperties(on).containsKey("p2")); + assertEquals("value2", ObjectNameUtil.getAdditionalPropertiesOfRuntimeBeanName(on).get("p2")); + + ObjectName pattern = ObjectNameUtil.createRuntimeBeanPattern(null, instanceName); + assertPattern(on, pattern); + } + + @Test + public void testModuleIdentifier() throws Exception { + ModuleIdentifier mi = new ModuleIdentifier(moduleName, instanceName); + ObjectName on = ObjectNameUtil.createReadOnlyModuleON(mi); + assertEquals(moduleName, ObjectNameUtil.getFactoryName(on)); + assertEquals(instanceName, ObjectNameUtil.getInstanceName(on)); + + assertEquals(mi, ObjectNameUtil.fromON(on, ObjectNameUtil.TYPE_MODULE)); + } + + @Test + public void testChecks() throws Exception { + final ObjectName on = ObjectNameUtil.createON("customDomain", ObjectNameUtil.TYPE_KEY, ObjectNameUtil.TYPE_MODULE); + + assertFailure(new Runnable() { + @Override + public void run() { + ObjectNameUtil.checkTypeOneOf(on, ObjectNameUtil.TYPE_RUNTIME_BEAN, ObjectNameUtil.TYPE_CONFIG_TRANSACTION); + } + }, IllegalArgumentException.class); + + assertFailure(new Runnable() { + @Override + public void run() { + ObjectNameUtil.checkType(on, ObjectNameUtil.TYPE_RUNTIME_BEAN); + } + }, IllegalArgumentException.class); + + assertFailure(new Runnable() { + @Override + public void run() { + ObjectNameUtil.checkDomain(on); + } + }, IllegalArgumentException.class); + } + + private void assertFailure(Runnable test, Class ex) { + try { + test.run(); + } catch(Exception e) { + Assert.assertTrue("Failed with wrong exception: " + Throwables.getStackTraceAsString(e), + e.getClass().isAssignableFrom(ex)); + return; + } + + fail(test + " should have failed on " + ex); + } +} diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java index 720b7197ea..375ef59487 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java @@ -7,6 +7,8 @@ */ package org.opendaylight.controller.config.manager.impl.osgi; +import com.google.common.annotations.VisibleForTesting; +import javax.management.ObjectName; import org.opendaylight.controller.config.api.ConflictingVersionException; import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.jmx.CommitStatus; @@ -17,8 +19,6 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.management.ObjectName; - /** * Every time factory is added or removed, blank transaction is triggered to handle * {@link org.opendaylight.controller.config.spi.ModuleFactory#getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory, org.osgi.framework.BundleContext)} @@ -27,10 +27,29 @@ import javax.management.ObjectName; public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer { private static final Logger logger = LoggerFactory.getLogger(BlankTransactionServiceTracker.class); - private final ConfigRegistryImpl configRegistry; + public static final int DEFAULT_MAX_ATTEMPTS = 10; - public BlankTransactionServiceTracker(ConfigRegistryImpl configRegistry) { - this.configRegistry = configRegistry; + private final BlankTransaction blankTransaction; + private int maxAttempts; + + public BlankTransactionServiceTracker(final ConfigRegistryImpl configRegistry) { + this(new BlankTransaction() { + @Override + public CommitStatus hit() throws ValidationException, ConflictingVersionException { + ObjectName tx = configRegistry.beginConfig(true); + return configRegistry.commitConfig(tx); + } + }); + } + + public BlankTransactionServiceTracker(final BlankTransaction blankTransaction) { + this(blankTransaction, DEFAULT_MAX_ATTEMPTS); + } + + @VisibleForTesting + BlankTransactionServiceTracker(final BlankTransaction blankTx, final int maxAttempts) { + this.blankTransaction = blankTx; + this.maxAttempts = maxAttempts; } @Override @@ -42,13 +61,10 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer< synchronized void blankTransaction() { // race condition check: config-persister might push new configuration while server is starting up. ConflictingVersionException lastException = null; - int maxAttempts = 10; for (int i = 0; i < maxAttempts; i++) { try { // create transaction - boolean blankTransaction = true; - ObjectName tx = configRegistry.beginConfig(blankTransaction); - CommitStatus commitStatus = configRegistry.commitConfig(tx); + CommitStatus commitStatus = blankTransaction.hit(); logger.debug("Committed blank transaction with status {}", commitStatus); return; } catch (ConflictingVersionException e) { @@ -77,4 +93,9 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer< public void removedService(ServiceReference moduleFactoryServiceReference, Object o) { blankTransaction(); } + + @VisibleForTesting + static interface BlankTransaction { + CommitStatus hit() throws ValidationException, ConflictingVersionException; + } } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java index 05ca43c3e2..3015ed229e 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.config.manager.impl.osgi; import static java.lang.String.format; +import com.google.common.annotations.VisibleForTesting; import java.io.InputStream; import java.net.URL; import java.util.List; @@ -70,9 +71,10 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer registerFactory(String factoryClassName, Bundle bundle) { + @VisibleForTesting + protected static ServiceRegistration registerFactory(String factoryClassName, Bundle bundle) { String errorMessage; + Exception ex = null; try { Class clazz = bundle.loadClass(factoryClassName); if (ModuleFactory.class.isAssignableFrom(clazz)) { @@ -86,10 +88,12 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer> getOsgiRegistrationTypes( Class configBeanClass) { - // TODO test with service interface hierarchy Set> serviceInterfaces = getServiceInterfaces(configBeanClass); Set> result = new HashSet<>(); for (Class clazz : serviceInterfaces) { diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java index e84337756e..f1072a76ae 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.config.manager.impl.util; import org.opendaylight.controller.config.spi.ModuleFactory; import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName; +import org.opendaylight.yangtools.yang.common.QName; import org.osgi.framework.BundleContext; import java.util.HashSet; @@ -31,9 +32,7 @@ public class ModuleQNameUtil { inspected = inspected.getSuperclass(); } if (annotation != null) { - // FIXME - String qName = "(" + annotation.namespace() + "?revision=" + annotation.revision() + ")" + annotation.name(); - result.add(qName); + result.add(QName.create(annotation.namespace(), annotation.revision(), annotation.name()).toString()); } } return result; diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java index 8873596642..2df28f0a15 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java @@ -8,6 +8,11 @@ package org.opendaylight.controller.config.manager.impl.util; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.osgi.util.tracker.BundleTracker; @@ -15,12 +20,6 @@ import org.osgi.util.tracker.ServiceTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.List; -import java.util.ListIterator; - -import static com.google.common.base.Preconditions.checkNotNull; - public class OsgiRegistrationUtil { private static final Logger logger = LoggerFactory.getLogger(OsgiRegistrationUtil.class); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTrackerTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTrackerTest.java new file mode 100644 index 0000000000..471c98a676 --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTrackerTest.java @@ -0,0 +1,83 @@ +package org.opendaylight.controller.config.manager.impl.osgi; + +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertSame; +import static junit.framework.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.util.Collections; +import javax.management.ObjectName; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.ValidationException; +import org.opendaylight.controller.config.api.jmx.CommitStatus; +import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.ServiceReference; + +public class BlankTransactionServiceTrackerTest { + + @Mock + private BlankTransactionServiceTracker.BlankTransaction blankTx; + private BlankTransactionServiceTracker tracker; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn(new CommitStatus(Collections.emptyList(), Collections.emptyList(), Collections.emptyList())).when(blankTx).hit(); + tracker = new BlankTransactionServiceTracker(blankTx); + } + + @Test + public void testBlankTransaction() throws Exception { + tracker.addingService(getMockServiceReference()); + tracker.modifiedService(getMockServiceReference(), null); + tracker.removedService(getMockServiceReference(), null); + verify(blankTx, times(3)).hit(); + } + + @Test + public void testValidationException() throws Exception { + IllegalArgumentException argumentException = new IllegalArgumentException(); + ValidationException validationException = ValidationException.createForSingleException(new ModuleIdentifier("m", "i"), argumentException); + doThrow(validationException).when(blankTx).hit(); + try { + tracker.addingService(getMockServiceReference()); + } catch (Exception e) { + verify(blankTx, times(1)).hit(); + assertNotNull(e.getCause()); + assertSame(validationException, e.getCause()); + return; + } + + fail("Exception should have occurred for validation exception"); + } + + @Test + public void testConflictingException() throws Exception { + int maxAttempts = 2; + tracker = new BlankTransactionServiceTracker(blankTx, maxAttempts); + + final ConflictingVersionException ex = new ConflictingVersionException(); + doThrow(ex).when(blankTx).hit(); + try { + tracker.addingService(getMockServiceReference()); + } catch (Exception e) { + verify(blankTx, times(maxAttempts)).hit(); + return; + } + + fail("Exception should have occurred for conflicting exception"); + } + + private ServiceReference getMockServiceReference() { + return mock(ServiceReference.class); + } +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolverTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolverTest.java new file mode 100644 index 0000000000..dc3deddddc --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolverTest.java @@ -0,0 +1,104 @@ +package org.opendaylight.controller.config.manager.impl.osgi; + +import static junit.framework.Assert.fail; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.matchers.JUnitMatchers.containsString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import com.google.common.collect.Lists; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +public class BundleContextBackedModuleFactoriesResolverTest { + + @Mock + private BundleContext bundleContext; + private BundleContextBackedModuleFactoriesResolver resolver; + private ServiceReference s1; + private ServiceReference s2; + private ModuleFactory f1; + private ModuleFactory f2; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + s1 = getServiceRef(); + s2 = getServiceRef(); + doReturn(Lists.newArrayList(s1, s2)).when(bundleContext).getServiceReferences(ModuleFactory.class, null); + f1 = getMockFactory("f1"); + doReturn(f1).when(bundleContext).getService(s1); + f2 = getMockFactory("f2"); + doReturn(f2).when(bundleContext).getService(s2); + resolver = new BundleContextBackedModuleFactoriesResolver(bundleContext); + } + + private ModuleFactory getMockFactory(String name) { + ModuleFactory mock = mock(ModuleFactory.class); + doReturn(name).when(mock).toString(); + doReturn(name).when(mock).getImplementationName(); + return mock; + } + + private ServiceReference getServiceRef() { + ServiceReference mock = mock(ServiceReference.class); + doReturn("serviceRef").when(mock).toString(); + final Bundle bundle = mock(Bundle.class); + doReturn(bundleContext).when(bundle).getBundleContext(); + doReturn(bundle).when(mock).getBundle(); + return mock; + } + + @Test + public void testGetAllFactories() throws Exception { + Map> allFactories = resolver.getAllFactories(); + assertEquals(2, allFactories.size()); + assertTrue(allFactories.containsKey(f1.getImplementationName())); + assertEquals(f1, allFactories.get(f1.getImplementationName()).getKey()); + assertEquals(bundleContext, allFactories.get(f1.getImplementationName()).getValue()); + assertTrue(allFactories.containsKey(f2.getImplementationName())); + assertEquals(f2, allFactories.get(f2.getImplementationName()).getKey()); + assertEquals(bundleContext, allFactories.get(f2.getImplementationName()).getValue()); + } + + @Test + public void testDuplicateFactories() throws Exception { + doReturn(f1).when(bundleContext).getService(s2); + try { + resolver.getAllFactories(); + } catch (Exception e) { + assertThat(e.getMessage(), containsString(f1.getImplementationName())); + assertThat(e.getMessage(), containsString("unique")); + return; + } + + fail("Should fail with duplicate factory name"); + } + + @Test(expected = NullPointerException.class) + public void testNullFactory() throws Exception { + doReturn(null).when(bundleContext).getService(s2); + resolver.getAllFactories(); + } + + @Test(expected = IllegalStateException.class) + public void testNullFactoryName() throws Exception { + doReturn(null).when(f1).getImplementationName(); + resolver.getAllFactories(); + } + + @Test(expected = NullPointerException.class) + public void testNullBundleName() throws Exception { + doReturn(null).when(s1).getBundle(); + resolver.getAllFactories(); + } +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTrackerTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTrackerTest.java new file mode 100644 index 0000000000..9a3ba64419 --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTrackerTest.java @@ -0,0 +1,76 @@ +package org.opendaylight.controller.config.manager.impl.osgi; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verifyZeroInteractions; + +import com.google.common.util.concurrent.Futures; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.util.tracker.BundleTrackerCustomizer; + +public class ExtensibleBundleTrackerTest { + + @Mock + private BundleContext bundleContext; + @Mock + private Bundle bundle; + @Mock + private BundleEvent bundleEvent; + + @Mock + private BundleTrackerCustomizer primaryTracker; + @Mock + private BundleTrackerCustomizer additionalTracker; + + private ExtensibleBundleTracker extensibleBundleTracker; + private Object primaryValue = new Object(); + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn("bundle").when(bundle).toString(); + doReturn("bundleEvent").when(bundleEvent).toString(); + + doReturn(primaryValue).when(primaryTracker).addingBundle(bundle, bundleEvent); + doNothing().when(primaryTracker).modifiedBundle(bundle, bundleEvent, primaryValue); + doNothing().when(primaryTracker).removedBundle(bundle, bundleEvent, primaryValue); + + doReturn(new Object()).when(additionalTracker).addingBundle(bundle, bundleEvent); + doNothing().when(additionalTracker).modifiedBundle(bundle, bundleEvent, null); + doNothing().when(additionalTracker).removedBundle(bundle, bundleEvent, null); + extensibleBundleTracker = new ExtensibleBundleTracker<>(bundleContext, primaryTracker, additionalTracker); + } + + @Test + public void testAddingBundle() throws Exception { + assertEquals(primaryValue, extensibleBundleTracker.addingBundle(bundle, bundleEvent).get()); + InOrder inOrder = Mockito.inOrder(primaryTracker, additionalTracker); + inOrder.verify(primaryTracker).addingBundle(bundle, bundleEvent); + inOrder.verify(additionalTracker).addingBundle(bundle, bundleEvent); + } + + @Test + public void testRemovedBundle() throws Exception { + extensibleBundleTracker.removedBundle(bundle, bundleEvent, Futures.immediateFuture(primaryValue)); + InOrder inOrder = Mockito.inOrder(primaryTracker, additionalTracker); + inOrder.verify(primaryTracker).removedBundle(bundle, bundleEvent, primaryValue); + inOrder.verify(additionalTracker).removedBundle(bundle, bundleEvent, null); + } + + @Test + public void testRemovedBundleWithEx() throws Exception { + IllegalStateException throwable = new IllegalStateException(); + extensibleBundleTracker.removedBundle(bundle, bundleEvent, Futures.immediateFailedFuture(throwable)); + verifyZeroInteractions(primaryTracker); + verifyZeroInteractions(additionalTracker); + } +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTrackerTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTrackerTest.java new file mode 100644 index 0000000000..5b83412083 --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTrackerTest.java @@ -0,0 +1,193 @@ +package org.opendaylight.controller.config.manager.impl.osgi; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import java.util.Dictionary; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DependencyResolverFactory; +import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; +import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; +import org.opendaylight.controller.config.spi.Module; +import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.ServiceRegistration; + +public class ModuleFactoryBundleTrackerTest { + + @Mock + private Bundle bundle; + @Mock + private BundleContext context; + @Mock + private ServiceRegistration reg; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doAnswer(new Answer() { + @Override + public Object answer(final InvocationOnMock invocation) throws Throwable { + return getClass().getClassLoader().loadClass((String) invocation.getArguments()[0]); + } + }).when(bundle).loadClass(anyString()); + doReturn("mockBundle").when(bundle).toString(); + doReturn(context).when(bundle).getBundleContext(); + doReturn(reg).when(context).registerService(anyString(), anyObject(), any(Dictionary.class)); + } + + @Test + public void testRegisterFactory() throws Exception { + ModuleFactoryBundleTracker.registerFactory(TestingFactory.class.getName(), bundle); + verify(context).registerService(ModuleFactory.class.getName(), TestingFactory.currentInstance, null); + } + + @Test + public void testRegisterFactoryInstantiateEx() throws Exception { + try { + ModuleFactoryBundleTracker.registerFactory(WrongConstructorTestingFactory.class.getName(), bundle); + } catch (Exception e) { + verifyZeroInteractions(context); + assertNotNull(e.getCause()); + assertEquals(InstantiationException.class, e.getCause().getClass()); + return; + } + + fail("Cannot register without proper constructor"); + } + + @Test + public void testRegisterFactoryInstantiateExAccess() throws Exception { + try { + ModuleFactoryBundleTracker.registerFactory(NoAccessConstructorTestingFactory.class.getName(), bundle); + } catch (Exception e) { + verifyZeroInteractions(context); + assertNotNull(e.getCause()); + assertEquals(IllegalAccessException.class, e.getCause().getClass()); + return; + } + + fail("Cannot register without proper constructor"); + } + + @Test + public void testRegisterFactoryNotExtending() throws Exception { + try { + ModuleFactoryBundleTracker.registerFactory(NotExtendingTestingFactory.class.getName(), bundle); + } catch (Exception e) { + verifyZeroInteractions(context); + return; + } + + fail("Cannot register without extend"); + } + + @Test + public void testRegisterFactoryNotExisting() throws Exception { + try { + ModuleFactoryBundleTracker.registerFactory("Unknown class", bundle); + } catch (Exception e) { + verifyZeroInteractions(context); + assertNotNull(e.getCause()); + assertEquals(ClassNotFoundException.class, e.getCause().getClass()); + return; + } + + fail("Cannot register without extend"); + } + + @Mock + private BlankTransactionServiceTracker blankTxTracker; + + @Test + public void testAddingBundle() throws Exception { + final ModuleFactoryBundleTracker tracker = new ModuleFactoryBundleTracker(blankTxTracker); + doReturn(getClass().getResource("/module-factories/module-factory-ok")).when(bundle).getEntry(anyString()); + tracker.addingBundle(bundle, mock(BundleEvent.class)); + verify(context).registerService(ModuleFactory.class.getName(), TestingFactory.currentInstance, null); + } + + @Test + public void testAddingBundleError() throws Exception { + final ModuleFactoryBundleTracker tracker = new ModuleFactoryBundleTracker(blankTxTracker); + doReturn(getClass().getResource("/module-factories/module-factory-fail")).when(bundle).getEntry(anyString()); + try { + tracker.addingBundle(bundle, mock(BundleEvent.class)); + } catch (Exception e) { + verifyZeroInteractions(context); + return; + } + + fail("Cannot register"); + } + + static class WrongConstructorTestingFactory extends TestingFactory { + WrongConstructorTestingFactory(String randomParam) { + } + } + + static class NotExtendingTestingFactory {} + + static class NoAccessConstructorTestingFactory extends TestingFactory { + private NoAccessConstructorTestingFactory() { + } + } + + static class TestingFactory implements ModuleFactory { + + static TestingFactory currentInstance; + + TestingFactory() { + currentInstance = this; + } + + @Override + public String getImplementationName() { + return "Testing"; + } + + @Override + public Module createModule(final String instanceName, final DependencyResolver dependencyResolver, final BundleContext bundleContext) { + throw new UnsupportedOperationException(); + } + + @Override + public Module createModule(final String instanceName, final DependencyResolver dependencyResolver, final DynamicMBeanWithInstance old, final BundleContext bundleContext) throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isModuleImplementingServiceInterface(final Class serviceInterface) { + throw new UnsupportedOperationException(); + } + + @Override + public Set> getImplementedServiceIntefaces() { + throw new UnsupportedOperationException(); + } + + @Override + public Set getDefaultModules(final DependencyResolverFactory dependencyResolverFactory, final BundleContext bundleContext) { + throw new UnsupportedOperationException(); + } + } +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java index 22ea528030..220bef03bc 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java @@ -9,20 +9,19 @@ package org.opendaylight.controller.config.manager.impl.util; import static org.junit.Assert.assertEquals; +import com.google.common.collect.Sets; +import java.util.Collections; import java.util.HashSet; import java.util.Set; - import javax.management.MXBean; - import org.junit.Test; import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; +import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingScheduledThreadPoolServiceInterface; import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.yangtools.concepts.Identifiable; -import com.google.common.collect.Sets; - public class InterfacesHelperTest { interface SuperA { @@ -46,10 +45,19 @@ public class InterfacesHelperTest { } + @ServiceInterfaceAnnotation(value = "a", osgiRegistrationType = SuperA.class, namespace = "n", revision = "r", localName = "l") + interface Service extends AbstractServiceInterface{} + @ServiceInterfaceAnnotation(value = "b", osgiRegistrationType = SuperC.class, namespace = "n", revision = "r", localName = "l") + interface SubService extends Service{} + abstract class SubClass extends SuperClass implements SubA, Module { } + abstract class SubClassWithService implements SubService, Module { + + } + @Test public void testGetAllInterfaces() { Set> expected = Sets.> newHashSet(SuperA.class, SuperBMXBean.class, SuperC.class, @@ -58,6 +66,19 @@ public class InterfacesHelperTest { InterfacesHelper.getAllInterfaces(SubClass.class)); } + @Test + public void testGetServiceInterfaces() throws Exception { + assertEquals(Collections.>emptySet(), InterfacesHelper.getServiceInterfaces(SubClass.class)); + assertEquals(Sets.>newHashSet(Service.class, SubService.class), InterfacesHelper.getServiceInterfaces(SubClassWithService.class)); + } + + @Test + public void testGetOsgiRegistrationTypes() throws Exception { + assertEquals(Collections.>emptySet(), InterfacesHelper.getOsgiRegistrationTypes(SubClass.class)); + assertEquals(Sets.>newHashSet(SuperA.class, SuperC.class), + InterfacesHelper.getOsgiRegistrationTypes(SubClassWithService.class)); + } + @Test public void testGetMXInterfaces() { Set> expected = Sets.> newHashSet(SuperBMXBean.class, SubA.class); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/ObjectNameUtilTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/ObjectNameUtilTest.java deleted file mode 100644 index fe322895ab..0000000000 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/ObjectNameUtilTest.java +++ /dev/null @@ -1,65 +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.config.manager.impl.util; - -import com.google.common.base.Throwables; -import com.google.common.collect.Sets; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.manager.impl.AbstractLockedPlatformMBeanServerTest; - -import javax.management.ObjectName; -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -public class ObjectNameUtilTest extends AbstractLockedPlatformMBeanServerTest { - private Set unregisterONs; - - @Before - public void initUnregisterList() { - unregisterONs = Sets.newHashSet(); - } - - @After - public void unregisterONs() { - Exception lastException = null; - for (ObjectName on : unregisterONs) { - try { - platformMBeanServer.unregisterMBean(on); - } catch (Exception e) { - lastException = e; - } - } - if (lastException != null) { - throw Throwables.propagate(lastException); - } - } - - @Test - public void testQuotation() throws Exception { - String serviceQName = "(namespace?revision=r)qname"; - String refName = "refName"; - String transaction = "transaction"; - ObjectName serviceReferenceON = ObjectNameUtil.createTransactionServiceON(transaction, serviceQName, refName); - assertFalse(serviceReferenceON.isPattern()); - assertEquals(serviceQName, ObjectNameUtil.getServiceQName(serviceReferenceON)); - assertEquals(refName, ObjectNameUtil.getReferenceName(serviceReferenceON)); - assertEquals(transaction, ObjectNameUtil.getTransactionName(serviceReferenceON)); - - serviceReferenceON = ObjectNameUtil.createReadOnlyServiceON(serviceQName, refName); - assertFalse(serviceReferenceON.isPattern()); - assertEquals(serviceQName, ObjectNameUtil.getServiceQName(serviceReferenceON)); - assertEquals(refName, ObjectNameUtil.getReferenceName(serviceReferenceON)); - assertEquals(null, ObjectNameUtil.getTransactionName(serviceReferenceON)); - - } -} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtilTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtilTest.java new file mode 100644 index 0000000000..fb59e3d515 --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtilTest.java @@ -0,0 +1,61 @@ +package org.opendaylight.controller.config.manager.impl.util; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mockito; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.BundleTracker; +import org.osgi.util.tracker.ServiceTracker; + +public class OsgiRegistrationUtilTest { + + @Test + public void testRegisterService() throws Exception { + final BundleContext bundleContext = mock(BundleContext.class); + ServiceRegistration registration = mockServiceRegistration(); + doReturn(registration).when(bundleContext).registerService(String.class, "string", null); + ServiceRegistration registration2 = mockServiceRegistration(); + doReturn(registration2).when(bundleContext).registerService(Object.class, "string", null); + + AutoCloseable aggregatedRegister = OsgiRegistrationUtil.registerService(bundleContext, "string", String.class, Object.class); + aggregatedRegister.close(); + + InOrder inOrder = Mockito.inOrder(registration, registration2); + inOrder.verify(registration2).unregister(); + inOrder.verify(registration).unregister(); + } + + @Test + public void testWrap() throws Exception { + final ServiceRegistration serviceReg = mockServiceRegistration(); + OsgiRegistrationUtil.wrap(serviceReg).close(); + verify(serviceReg).unregister(); + + final BundleTracker tracker = mock(BundleTracker.class); + doNothing().when(tracker).close(); + OsgiRegistrationUtil.wrap(tracker).close(); + verify(tracker).close(); + + final ServiceTracker sTracker = mock(ServiceTracker.class); + doNothing().when(sTracker).close(); + OsgiRegistrationUtil.wrap(sTracker).close(); + verify(sTracker).close(); + } + + private ServiceRegistration mockServiceRegistration() { + ServiceRegistration mock = mock(ServiceRegistration.class); + doNothing().when(mock).unregister(); + return mock; + } + + @Test + public void testAggregate() throws Exception { + + } +} \ No newline at end of file diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java index 0286400d7b..a7024ca39e 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java @@ -9,6 +9,6 @@ package org.opendaylight.controller.config.manager.testingservices.threadpool; import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName; -@ModuleQName(namespace = "namespace", revision = "revision", name = "name") +@ModuleQName(namespace = "namespace", revision = "2012-12-12", name = "name") public abstract class AbstractTestingFixedThreadPoolModuleFactory { } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java index 97d1c63ed2..4ba3dc8939 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java @@ -380,7 +380,8 @@ public class SimpleConfigurationTest extends AbstractConfigTest { @Test public void testQNames() { Set availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames(); - String expected = "(namespace?revision=revision)name"; + String expected = "(namespace?revision=2012-12-12)name"; + assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames); } diff --git a/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-fail b/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-fail new file mode 100644 index 0000000000..fbd810841f --- /dev/null +++ b/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-fail @@ -0,0 +1 @@ +org.opendaylight.controller.config.manager.impl.osgi.ModuleFactoryBundleTrackerTest$NotExtendingTestingFactory \ No newline at end of file diff --git a/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-ok b/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-ok new file mode 100644 index 0000000000..031b622bba --- /dev/null +++ b/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-ok @@ -0,0 +1 @@ +org.opendaylight.controller.config.manager.impl.osgi.ModuleFactoryBundleTrackerTest$TestingFactory \ No newline at end of file diff --git a/opendaylight/config/netconf-config-dispatcher/pom.xml b/opendaylight/config/netconf-config-dispatcher/pom.xml index b9d218ead1..1e5fcce609 100644 --- a/opendaylight/config/netconf-config-dispatcher/pom.xml +++ b/opendaylight/config/netconf-config-dispatcher/pom.xml @@ -27,6 +27,38 @@ ${project.groupId} netconf-client + + + ${project.groupId} + config-manager + test-jar + test + + + ${project.groupId} + config-manager + test + + + ${project.groupId} + config-util + test + + + ${project.groupId} + netty-threadgroup-config + test + + + ${project.groupId} + netty-timer-config + test + + + org.opendaylight.yangtools + mockito-configuration + test + diff --git a/opendaylight/config/netconf-config-dispatcher/src/test/java/org/opendaylight/controller/config/yang/config/netconf/client/dispatcher/NetconfClientDispatcherModuleTest.java b/opendaylight/config/netconf-config-dispatcher/src/test/java/org/opendaylight/controller/config/yang/config/netconf/client/dispatcher/NetconfClientDispatcherModuleTest.java new file mode 100644 index 0000000000..85477a0237 --- /dev/null +++ b/opendaylight/config/netconf-config-dispatcher/src/test/java/org/opendaylight/controller/config/yang/config/netconf/client/dispatcher/NetconfClientDispatcherModuleTest.java @@ -0,0 +1,102 @@ +package org.opendaylight.controller.config.yang.config.netconf.client.dispatcher; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; +import org.opendaylight.controller.config.api.jmx.CommitStatus; +import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; +import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; +import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; +import org.opendaylight.controller.config.yang.netty.threadgroup.NettyThreadgroupModuleFactory; +import org.opendaylight.controller.config.yang.netty.threadgroup.NettyThreadgroupModuleMXBean; +import org.opendaylight.controller.config.yang.netty.timer.HashedWheelTimerModuleFactory; + +public class NetconfClientDispatcherModuleTest extends AbstractConfigTest{ + + private NetconfClientDispatcherModuleFactory factory; + private final String instanceName = "dispatch"; + + @Before + public void setUp() { + factory = new NetconfClientDispatcherModuleFactory(); + super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,factory, + new NettyThreadgroupModuleFactory(), + new HashedWheelTimerModuleFactory())); + } + + @Test + public void testCreateBean() throws InstanceAlreadyExistsException, ValidationException, ConflictingVersionException { + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + + createInstance(transaction, instanceName, "timer", "thGroup"); + createInstance(transaction, instanceName + 2, "timer2", "thGroup2"); + transaction.validateConfig(); + CommitStatus status = transaction.commit(); + + assertBeanCount(2, factory.getImplementationName()); + assertStatus(status, 2 + 4, 0, 0); + } + + @Test + public void testReusingOldInstance() throws InstanceAlreadyExistsException, ConflictingVersionException, ValidationException { + + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + createInstance(transaction, instanceName, "timer", "thGroup"); + + transaction.commit(); + + transaction = configRegistryClient.createTransaction(); + assertBeanCount(1, factory.getImplementationName()); + CommitStatus status = transaction.commit(); + + assertBeanCount(1, factory.getImplementationName()); + assertStatus(status, 0, 0, 3); + } + + @Test + public void testReconfigure() throws InstanceAlreadyExistsException, ConflictingVersionException, + ValidationException, InstanceNotFoundException { + + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + createInstance(transaction, instanceName, "timer", "thGroup"); + + transaction.commit(); + + transaction = configRegistryClient.createTransaction(); + assertBeanCount(1, factory.getImplementationName()); + NetconfClientDispatcherModuleMXBean mxBean = transaction.newMBeanProxy( + transaction.lookupConfigBean(NetconfClientDispatcherModuleFactory.NAME, instanceName), + NetconfClientDispatcherModuleMXBean.class); + mxBean.setBossThreadGroup(getThreadGroup(transaction, "group2")); + CommitStatus status = transaction.commit(); + + assertBeanCount(1, factory.getImplementationName()); + assertStatus(status, 1, 1, 2); + } + + private ObjectName createInstance(ConfigTransactionJMXClient transaction, String instanceName, String timerName, String threadGroupName) + throws InstanceAlreadyExistsException { + ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), instanceName); + NetconfClientDispatcherModuleMXBean mxBean = transaction.newMBeanProxy(nameCreated, NetconfClientDispatcherModuleMXBean.class); + ObjectName thGroup = getThreadGroup(transaction, threadGroupName); + mxBean.setBossThreadGroup(thGroup); + mxBean.setWorkerThreadGroup(thGroup); + mxBean.setTimer(getTimer(transaction, timerName)); + return nameCreated; + } + + private ObjectName getTimer(ConfigTransactionJMXClient transaction, String name) throws InstanceAlreadyExistsException { + return transaction.createModule(HashedWheelTimerModuleFactory.NAME, name); + } + + private ObjectName getThreadGroup(ConfigTransactionJMXClient transaction, String name) throws InstanceAlreadyExistsException { + ObjectName nameCreated = transaction.createModule(NettyThreadgroupModuleFactory.NAME, name); + NettyThreadgroupModuleMXBean mxBean = transaction.newMXBeanProxy(nameCreated, NettyThreadgroupModuleMXBean.class); + mxBean.setThreadCount(1); + return nameCreated; + } +} diff --git a/opendaylight/config/netty-event-executor-config/src/test/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleTest.java b/opendaylight/config/netty-event-executor-config/src/test/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleTest.java new file mode 100644 index 0000000000..4cc9cc3dde --- /dev/null +++ b/opendaylight/config/netty-event-executor-config/src/test/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleTest.java @@ -0,0 +1,71 @@ +/* + * 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.config.yang.netty.eventexecutor; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.ObjectName; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; +import org.opendaylight.controller.config.api.jmx.CommitStatus; +import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; +import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; +import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; + +public class ImmediateEventExecutorModuleTest extends AbstractConfigTest { + + private GlobalEventExecutorModuleFactory factory; + private final String instanceName = ImmediateEventExecutorModuleFactory.SINGLETON_NAME; + + @Before + public void setUp() { + factory = new GlobalEventExecutorModuleFactory(); + super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,factory)); + } + + @Test + public void testCreateBean() throws InstanceAlreadyExistsException, ValidationException, + ConflictingVersionException { + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + + createInstance(transaction, instanceName); + + transaction.validateConfig(); + CommitStatus status = transaction.commit(); + + assertBeanCount(1, factory.getImplementationName()); + assertStatus(status, 1, 0, 0); + } + + @Test + public void testReusingOldInstance() throws InstanceAlreadyExistsException, ConflictingVersionException, + ValidationException { + + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + createInstance(transaction, instanceName); + + transaction.commit(); + + transaction = configRegistryClient.createTransaction(); + assertBeanCount(1, factory.getImplementationName()); + CommitStatus status = transaction.commit(); + + assertBeanCount(1, factory.getImplementationName()); + assertStatus(status, 0, 0, 1); + } + + private ObjectName createInstance(ConfigTransactionJMXClient transaction, String instanceName) + throws InstanceAlreadyExistsException { + ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), instanceName); + transaction.newMBeanProxy(nameCreated, ImmediateEventExecutorModuleMXBean.class); + return nameCreated; + } + +} diff --git a/opendaylight/config/netty-timer-config/src/test/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java b/opendaylight/config/netty-timer-config/src/test/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java similarity index 99% rename from opendaylight/config/netty-timer-config/src/test/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java rename to opendaylight/config/netty-timer-config/src/test/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java index 1b5668b610..5fe5f9496e 100644 --- a/opendaylight/config/netty-timer-config/src/test/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java +++ b/opendaylight/config/netty-timer-config/src/test/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java @@ -34,7 +34,7 @@ public class HashedWheelTimerModuleTest extends AbstractConfigTest { public void setUp() { factory = new HashedWheelTimerModuleFactory(); threadFactory = new NamingThreadFactoryModuleFactory(); - super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(factory, threadFactory)); + super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, factory, threadFactory)); } public void testValidationExceptionTickDuration() throws InstanceAlreadyExistsException { diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.java b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.java index 9724d31f9a..29ac12393a 100644 --- a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.java +++ b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.java @@ -7,21 +7,20 @@ */ package org.opendaylight.controller.md.inventory.manager; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ExecutionException; import java.util.concurrent.LinkedBlockingDeque; - -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Preconditions; - class FlowCapableInventoryProvider implements AutoCloseable, Runnable { private static final Logger LOG = LoggerFactory.getLogger(FlowCapableInventoryProvider.class); private static final int QUEUE_DEPTH = 500; @@ -29,12 +28,13 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable { private final BlockingQueue queue = new LinkedBlockingDeque<>(QUEUE_DEPTH); private final NotificationProviderService notificationService; - private final DataProviderService dataService; + + private final DataBroker dataBroker; private ListenerRegistration listenerRegistration; private Thread thread; - FlowCapableInventoryProvider(final DataProviderService dataService, final NotificationProviderService notificationService) { - this.dataService = Preconditions.checkNotNull(dataService); + FlowCapableInventoryProvider(final DataBroker dataBroker, final NotificationProviderService notificationService) { + this.dataBroker = Preconditions.checkNotNull(dataBroker); this.notificationService = Preconditions.checkNotNull(notificationService); } @@ -82,10 +82,10 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable { @Override public void run() { try { - for (;;) { + for (; ; ) { InventoryOperation op = queue.take(); - final DataModificationTransaction tx = dataService.beginTransaction(); + final ReadWriteTransaction tx = dataBroker.newReadWriteTransaction(); LOG.debug("New operations available, starting transaction {}", tx.getIdentifier()); int ops = 0; @@ -102,14 +102,18 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable { LOG.debug("Processed {} operations, submitting transaction {}", ops, tx.getIdentifier()); - try { - final RpcResult result = tx.commit().get(); - if(!result.isSuccessful()) { - LOG.error("Transaction {} failed", tx.getIdentifier()); + final CheckedFuture result = tx.submit(); + Futures.addCallback(result, new FutureCallback() { + @Override + public void onSuccess(Void aVoid) { + //NOOP + } + + @Override + public void onFailure(Throwable throwable) { + LOG.error("Transaction {} failed.", tx.getIdentifier(), throwable); } - } catch (ExecutionException e) { - LOG.warn("Failed to commit inventory change", e.getCause()); - } + }); } } catch (InterruptedException e) { LOG.info("Processing interrupted, terminating", e); diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryActivator.java b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryActivator.java index 5bcae367e3..991611aebc 100644 --- a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryActivator.java +++ b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryActivator.java @@ -7,10 +7,10 @@ */ package org.opendaylight.controller.md.inventory.manager; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,11 +21,11 @@ public class InventoryActivator extends AbstractBindingAwareProvider { @Override public void onSessionInitiated(final ProviderContext session) { - DataProviderService salDataService = session.getSALService(DataProviderService.class); + DataBroker dataBroker = session.getSALService(DataBroker.class); NotificationProviderService salNotifiService = session.getSALService(NotificationProviderService.class); - provider = new FlowCapableInventoryProvider(salDataService, salNotifiService); + provider = new FlowCapableInventoryProvider(dataBroker, salNotifiService); provider.start(); } diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryOperation.java b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryOperation.java index 3be5fcf643..cfc9579983 100644 --- a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryOperation.java +++ b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryOperation.java @@ -7,10 +7,10 @@ */ package org.opendaylight.controller.md.inventory.manager; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; interface InventoryOperation { - void applyOperation(DataModificationTransaction tx); + void applyOperation(ReadWriteTransaction tx); } diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/NodeChangeCommiter.java b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/NodeChangeCommiter.java index 3db3c93fcc..57ec893076 100644 --- a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/NodeChangeCommiter.java +++ b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/NodeChangeCommiter.java @@ -7,11 +7,20 @@ */ package org.opendaylight.controller.md.inventory.manager; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated; @@ -25,13 +34,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.No import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Preconditions; - class NodeChangeCommiter implements OpendaylightInventoryListener { private static final Logger LOG = LoggerFactory.getLogger(NodeChangeCommiter.class); @@ -43,21 +51,23 @@ class NodeChangeCommiter implements OpendaylightInventoryListener { @Override public synchronized void onNodeConnectorRemoved(final NodeConnectorRemoved connector) { + LOG.debug("Node connector removed notification received."); manager.enqueue(new InventoryOperation() { @Override - public void applyOperation(final DataModificationTransaction tx) { + public void applyOperation(final ReadWriteTransaction tx) { final NodeConnectorRef ref = connector.getNodeConnectorRef(); LOG.debug("removing node connector {} ", ref.getValue()); - tx.removeOperationalData(ref.getValue()); + tx.delete(LogicalDatastoreType.OPERATIONAL, ref.getValue()); } }); } @Override public synchronized void onNodeConnectorUpdated(final NodeConnectorUpdated connector) { + LOG.debug("Node connector updated notification received."); manager.enqueue(new InventoryOperation() { @Override - public void applyOperation(final DataModificationTransaction tx) { + public void applyOperation(final ReadWriteTransaction tx) { final NodeConnectorRef ref = connector.getNodeConnectorRef(); final NodeConnectorBuilder data = new NodeConnectorBuilder(connector); data.setKey(new NodeConnectorKey(connector.getId())); @@ -68,22 +78,23 @@ class NodeChangeCommiter implements OpendaylightInventoryListener { final FlowCapableNodeConnector augment = InventoryMapping.toInventoryAugment(flowConnector); data.addAugmentation(FlowCapableNodeConnector.class, augment); } - InstanceIdentifier value = ref.getValue(); + InstanceIdentifier value = (InstanceIdentifier) ref.getValue(); LOG.debug("updating node connector : {}.", value); NodeConnector build = data.build(); - tx.putOperationalData(value, build); + tx.put(LogicalDatastoreType.OPERATIONAL, value, build); } }); } @Override public synchronized void onNodeRemoved(final NodeRemoved node) { + LOG.debug("Node removed notification received."); manager.enqueue(new InventoryOperation() { @Override - public void applyOperation(final DataModificationTransaction tx) { + public void applyOperation(final ReadWriteTransaction tx) { final NodeRef ref = node.getNodeRef(); LOG.debug("removing node : {}", ref.getValue()); - tx.removeOperationalData((ref.getValue())); + tx.delete(LogicalDatastoreType.OPERATIONAL, ref.getValue()); } }); } @@ -94,23 +105,62 @@ class NodeChangeCommiter implements OpendaylightInventoryListener { if (flowNode == null) { return; } - + LOG.debug("Node updated notification received."); manager.enqueue(new InventoryOperation() { @Override - public void applyOperation(final DataModificationTransaction tx) { + public void applyOperation(ReadWriteTransaction tx) { final NodeRef ref = node.getNodeRef(); + @SuppressWarnings("unchecked") + InstanceIdentifierBuilder builder = ((InstanceIdentifier) ref.getValue()).builder(); + InstanceIdentifierBuilder augmentation = builder.augmentation(FlowCapableNode.class); + final InstanceIdentifier path = augmentation.build(); + CheckedFuture readFuture = tx.read(LogicalDatastoreType.OPERATIONAL, path); + Futures.addCallback(readFuture, new FutureCallback>() { + @Override + public void onSuccess(Optional optional) { + enqueueWriteNodeDataTx(node, flowNode, path); + if (!optional.isPresent()) { + enqueuePutTable0Tx(ref); + } + } + + @Override + public void onFailure(Throwable throwable) { + LOG.debug(String.format("Can't retrieve node data for node %s. Writing node data with table0.", node)); + enqueueWriteNodeDataTx(node, flowNode, path); + enqueuePutTable0Tx(ref); + } + }); + } + }); + } + + private void enqueueWriteNodeDataTx(final NodeUpdated node, final FlowCapableNodeUpdated flowNode, final InstanceIdentifier path) { + manager.enqueue(new InventoryOperation() { + @Override + public void applyOperation(final ReadWriteTransaction tx) { final NodeBuilder nodeBuilder = new NodeBuilder(node); nodeBuilder.setKey(new NodeKey(node.getId())); final FlowCapableNode augment = InventoryMapping.toInventoryAugment(flowNode); nodeBuilder.addAugmentation(FlowCapableNode.class, augment); - - @SuppressWarnings("unchecked") - InstanceIdentifierBuilder builder = ((InstanceIdentifier) ref.getValue()).builder(); - InstanceIdentifierBuilder augmentation = builder.augmentation(FlowCapableNode.class); - final InstanceIdentifier path = augmentation.build(); LOG.debug("updating node :{} ", path); - tx.putOperationalData(path, augment); + tx.put(LogicalDatastoreType.OPERATIONAL, path, augment); + } + }); + } + + private void enqueuePutTable0Tx(final NodeRef ref) { + manager.enqueue(new InventoryOperation() { + @Override + public void applyOperation(ReadWriteTransaction tx) { + final TableKey tKey = new TableKey((short) 0); + final InstanceIdentifier tableIdentifier = + ((InstanceIdentifier) ref.getValue()).augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tKey)); + TableBuilder tableBuilder = new TableBuilder(); + Table table0 = tableBuilder.setId((short) 0).build(); + LOG.debug("writing table :{} ", tableIdentifier); + tx.put(LogicalDatastoreType.OPERATIONAL, tableIdentifier, table0, true); } }); } diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/mdsal/CompositeModificationPayload.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/shard/CompositeModificationPayload.java similarity index 91% rename from opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/mdsal/CompositeModificationPayload.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/shard/CompositeModificationPayload.java index 87b246bd7e..ca578a88aa 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/mdsal/CompositeModificationPayload.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/shard/CompositeModificationPayload.java @@ -1,13 +1,13 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // source: CompositeModificationPayload.proto -package org.opendaylight.controller.mdsal; +package org.opendaylight.controller.protobuff.messages.shard; public final class CompositeModificationPayload { private CompositeModificationPayload() {} public static void registerAllExtensions( com.google.protobuf.ExtensionRegistry registry) { - registry.add(org.opendaylight.controller.mdsal.CompositeModificationPayload.modification); + registry.add(org.opendaylight.controller.protobuff.messages.shard.CompositeModificationPayload.modification); } public static final int MODIFICATION_FIELD_NUMBER = 2; /** @@ -36,7 +36,8 @@ public final class CompositeModificationPayload { "daylight.controller.cluster.raft.AppendE" + "ntries.ReplicatedLogEntry.Payload\030\002 \001(\0132" + "8.org.opendaylight.controller.mdsal.Comp" + - "ositeModification" + "ositeModificationB6\n4org.opendaylight.co" + + "ntroller.protobuff.messages.shard" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/resources/CompositeModificationPayload.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/CompositeModificationPayload.proto index b571cd25c5..e824e9e3ae 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/resources/CompositeModificationPayload.proto +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/CompositeModificationPayload.proto @@ -4,6 +4,8 @@ import "AppendEntriesMessages.proto"; import "Common.proto"; import "Persistent.proto"; +option java_package = "org.opendaylight.controller.protobuff.messages.shard"; + extend org.opendaylight.controller.cluster.raft.AppendEntries.ReplicatedLogEntry.Payload { optional CompositeModification modification=2; } diff --git a/opendaylight/md-sal/sal-clustering-config/pom.xml b/opendaylight/md-sal/sal-clustering-config/pom.xml index d726823b98..a42a66aed1 100644 --- a/opendaylight/md-sal/sal-clustering-config/pom.xml +++ b/opendaylight/md-sal/sal-clustering-config/pom.xml @@ -18,29 +18,5 @@ Configuration files for md-sal clustering jar - - - org.codehaus.mojo - build-helper-maven-plugin - - - attach-artifacts - - attach-artifact - - package - - - - ${project.build.directory}/classes/initial/*.conf - xml - config - - - - - - - diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/CompositeModificationPayload.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/CompositeModificationPayload.java index d0abb20718..36c0447b6e 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/CompositeModificationPayload.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/CompositeModificationPayload.java @@ -35,7 +35,8 @@ public class CompositeModificationPayload extends Payload implements @Override public Map encode() { Preconditions.checkState(modification!=null); Map map = new HashMap<>(); - map.put(org.opendaylight.controller.mdsal.CompositeModificationPayload.modification, this.modification); + map.put( + org.opendaylight.controller.protobuff.messages.shard.CompositeModificationPayload.modification, this.modification); return map; } @@ -43,7 +44,7 @@ public class CompositeModificationPayload extends Payload implements AppendEntriesMessages.AppendEntries.ReplicatedLogEntry.Payload payload) { PersistentMessages.CompositeModification modification = payload .getExtension( - org.opendaylight.controller.mdsal.CompositeModificationPayload.modification); + org.opendaylight.controller.protobuff.messages.shard.CompositeModificationPayload.modification); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/application.conf b/opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/application.conf index 874d3fcb90..459eb78903 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/application.conf +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/application.conf @@ -17,13 +17,13 @@ odl-cluster{ log-remote-lifecycle-events = off netty.tcp { - hostname = "localhost" + hostname = "127.0.0.1" port = 2551 } } cluster { - seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"] + seed-nodes = ["akka.tcp://opendaylight-rpc@127.0.0.1:2551"] auto-down-unreachable-after = 10s } @@ -52,13 +52,13 @@ memberA{ log-remote-lifecycle-events = off netty.tcp { - hostname = "localhost" + hostname = "127.0.0.1" port = 2551 } } cluster { - seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"] + seed-nodes = ["akka.tcp://opendaylight-rpc@127.0.0.1:2551"] auto-down-unreachable-after = 10s } @@ -77,13 +77,13 @@ memberB{ log-remote-lifecycle-events = off netty.tcp { - hostname = "localhost" + hostname = "127.0.0.1" port = 2552 } } cluster { - seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"] + seed-nodes = ["akka.tcp://opendaylight-rpc@127.0.0.1:2551"] auto-down-unreachable-after = 10s } @@ -102,13 +102,13 @@ memberC{ log-remote-lifecycle-events = off netty.tcp { - hostname = "localhost" + hostname = "127.0.0.1" port = 2553 } } cluster { - seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"] + seed-nodes = ["akka.tcp://opendaylight-rpc@127.0.0.1:2551"] auto-down-unreachable-after = 10s } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java index edf7388a76..1a14de6f5d 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java @@ -32,6 +32,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.f import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,11 +53,10 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker flowRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(item.getTableId())) - .child(Flow.class,item.getFlow().getKey()) - .augmentation(FlowStatisticsData.class).toInstance(); + KeyedInstanceIdentifier flowRef = getNodeIdentifier() + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(item.getTableId())) + .child(Flow.class, item.getFlow().getKey()); trans.removeOperationalData(flowRef); } diff --git a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java index 6dbfd7225b..d7ce9485c6 100644 --- a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java +++ b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java @@ -15,8 +15,14 @@ import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMap import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNode; import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNodeId; -import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryListener; @@ -41,10 +47,12 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology. import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -import com.google.common.base.Preconditions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, OpendaylightInventoryListener { + + private final Logger LOG = LoggerFactory.getLogger(FlowCapableTopologyExporter.class); private final InstanceIdentifier topology; private final OperationProcessor processor; @@ -55,13 +63,21 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open @Override public void onNodeRemoved(final NodeRemoved notification) { + + final NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeRef()).getId()); + final InstanceIdentifier nodeInstance = toNodeIdentifier(notification.getNodeRef()); + processor.enqueueOperation(new TopologyOperation() { @Override - public void applyOperation(final DataModificationTransaction transaction) { - NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeRef()).getId()); - InstanceIdentifier nodeInstance = toNodeIdentifier(notification.getNodeRef()); - transaction.removeOperationalData(nodeInstance); - removeAffectedLinks(transaction, nodeId); + public void applyOperation(final ReadWriteTransaction transaction) { + removeAffectedLinks(nodeId); + } + }); + + processor.enqueueOperation(new TopologyOperation() { + @Override + public void applyOperation(ReadWriteTransaction transaction) { + transaction.delete(LogicalDatastoreType.OPERATIONAL, nodeInstance); } }); } @@ -72,10 +88,10 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open if (fcnu != null) { processor.enqueueOperation(new TopologyOperation() { @Override - public void applyOperation(final DataModificationTransaction transaction) { - Node node = toTopologyNode(toTopologyNodeId(notification.getId()), notification.getNodeRef()); - InstanceIdentifier path = getNodePath(toTopologyNodeId(notification.getId())); - transaction.putOperationalData(path, node); + public void applyOperation(final ReadWriteTransaction transaction) { + final Node node = toTopologyNode(toTopologyNodeId(notification.getId()), notification.getNodeRef()); + final InstanceIdentifier path = getNodePath(toTopologyNodeId(notification.getId())); + transaction.put(LogicalDatastoreType.OPERATIONAL, path, node); } }); } @@ -83,15 +99,22 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open @Override public void onNodeConnectorRemoved(final NodeConnectorRemoved notification) { + + final InstanceIdentifier tpInstance = toTerminationPointIdentifier(notification + .getNodeConnectorRef()); + processor.enqueueOperation(new TopologyOperation() { @Override - public void applyOperation(final DataModificationTransaction transaction) { - InstanceIdentifier tpInstance = toTerminationPointIdentifier(notification - .getNodeConnectorRef()); - TpId tpId = toTerminationPointId(getNodeConnectorKey(notification.getNodeConnectorRef()).getId()); + public void applyOperation(final ReadWriteTransaction transaction) { + final TpId tpId = toTerminationPointId(getNodeConnectorKey(notification.getNodeConnectorRef()).getId()); + removeAffectedLinks(tpId); + } + }); - transaction.removeOperationalData(tpInstance); - removeAffectedLinks(transaction, tpId); + processor.enqueueOperation(new TopologyOperation() { + @Override + public void applyOperation(ReadWriteTransaction transaction) { + transaction.delete(LogicalDatastoreType.OPERATIONAL, tpInstance); } }); } @@ -102,16 +125,15 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open if (fcncu != null) { processor.enqueueOperation(new TopologyOperation() { @Override - public void applyOperation(final DataModificationTransaction transaction) { - NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeConnectorRef()).getId()); + public void applyOperation(final ReadWriteTransaction transaction) { + final NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeConnectorRef()).getId()); TerminationPoint point = toTerminationPoint(toTerminationPointId(notification.getId()), notification.getNodeConnectorRef()); - InstanceIdentifier path = tpPath(nodeId, point.getKey().getTpId()); - - transaction.putOperationalData(path, point); + final InstanceIdentifier path = tpPath(nodeId, point.getKey().getTpId()); + transaction.put(LogicalDatastoreType.OPERATIONAL, path, point); if ((fcncu.getState() != null && fcncu.getState().isLinkDown()) || (fcncu.getConfiguration() != null && fcncu.getConfiguration().isPORTDOWN())) { - removeAffectedLinks(transaction, point.getTpId()); + removeAffectedLinks(point.getTpId()); } } }); @@ -122,10 +144,10 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open public void onLinkDiscovered(final LinkDiscovered notification) { processor.enqueueOperation(new TopologyOperation() { @Override - public void applyOperation(final DataModificationTransaction transaction) { - Link link = toTopologyLink(notification); - InstanceIdentifier path = linkPath(link); - transaction.putOperationalData(path, link); + public void applyOperation(final ReadWriteTransaction transaction) { + final Link link = toTopologyLink(notification); + final InstanceIdentifier path = linkPath(link); + transaction.put(LogicalDatastoreType.OPERATIONAL, path, link); } }); } @@ -139,8 +161,8 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open public void onLinkRemoved(final LinkRemoved notification) { processor.enqueueOperation(new TopologyOperation() { @Override - public void applyOperation(final DataModificationTransaction transaction) { - transaction.removeOperationalData(linkPath(toTopologyLink(notification))); + public void applyOperation(final ReadWriteTransaction transaction) { + transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(toTopologyLink(notification))); } }); } @@ -162,28 +184,58 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open return tpPath(toTopologyNodeId(invNodeKey.getId()), toTerminationPointId(invNodeConnectorKey.getId())); } - private void removeAffectedLinks(final DataModificationTransaction transaction, final NodeId id) { - TypeSafeDataReader reader = TypeSafeDataReader.forReader(transaction); - Topology topologyData = reader.readOperationalData(topology); - if (topologyData != null) { - for (Link link : topologyData.getLink()) { - if (id.equals(link.getSource().getSourceNode()) || id.equals(link.getDestination().getDestNode())) { - transaction.removeOperationalData(linkPath(link)); - } + private void removeAffectedLinks(final NodeId id) { + processor.enqueueOperation(new TopologyOperation() { + @Override + public void applyOperation(final ReadWriteTransaction transaction) { + CheckedFuture, ReadFailedException> topologyDataFuture = transaction.read(LogicalDatastoreType.OPERATIONAL, topology); + Futures.addCallback(topologyDataFuture, new FutureCallback>() { + @Override + public void onSuccess(Optional topologyOptional) { + if (topologyOptional.isPresent()) { + Topology topologyData = topologyOptional.get(); + for (Link link : topologyData.getLink()) { + if (id.equals(link.getSource().getSourceNode()) || id.equals(link.getDestination().getDestNode())) { + transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(link)); + } + } + } + } + + @Override + public void onFailure(Throwable throwable) { + LOG.error("Error reading topology data for topology {}", topology, throwable); + } + }); } - } + }); } - private void removeAffectedLinks(final DataModificationTransaction transaction, final TpId id) { - TypeSafeDataReader reader = TypeSafeDataReader.forReader(transaction); - Topology topologyData = reader.readOperationalData(topology); - if (topologyData != null) { - for (Link link : topologyData.getLink()) { - if (id.equals(link.getSource().getSourceTp()) || id.equals(link.getDestination().getDestTp())) { - transaction.removeOperationalData(linkPath(link)); - } + private void removeAffectedLinks(final TpId id) { + processor.enqueueOperation(new TopologyOperation() { + @Override + public void applyOperation(final ReadWriteTransaction transaction) { + CheckedFuture, ReadFailedException> topologyDataFuture = transaction.read(LogicalDatastoreType.OPERATIONAL, topology); + Futures.addCallback(topologyDataFuture, new FutureCallback>() { + @Override + public void onSuccess(Optional topologyOptional) { + if (topologyOptional.isPresent()) { + Topology topologyData = topologyOptional.get(); + for (Link link : topologyData.getLink()) { + if (id.equals(link.getSource().getSourceTp()) || id.equals(link.getDestination().getDestTp())) { + transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(link)); + } + } + } + } + + @Override + public void onFailure(Throwable throwable) { + LOG.error("Error reading topology data for topology {}", topology, throwable); + } + }); } - } + }); } private InstanceIdentifier getNodePath(final NodeId nodeId) { diff --git a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyProvider.java b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyProvider.java index a87971bc6b..0a3b9f6a6b 100644 --- a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyProvider.java +++ b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyProvider.java @@ -8,12 +8,12 @@ package org.opendaylight.md.controller.topology.manager; import java.util.concurrent.ExecutionException; - +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; @@ -38,7 +38,7 @@ public class FlowCapableTopologyProvider extends AbstractBindingAwareProvider im */ @Override public synchronized void onSessionInitiated(final ProviderContext session) { - final DataProviderService dataService = session.getSALService(DataProviderService.class); + final DataBroker dataBroker = session.getSALService(DataBroker.class); final NotificationProviderService notificationService = session.getSALService(NotificationProviderService.class); final String name = "flow:1"; @@ -48,14 +48,14 @@ public class FlowCapableTopologyProvider extends AbstractBindingAwareProvider im .child(Topology.class, key) .build(); - final OperationProcessor processor = new OperationProcessor(dataService); + final OperationProcessor processor = new OperationProcessor(dataBroker); final FlowCapableTopologyExporter listener = new FlowCapableTopologyExporter(processor, path); this.listenerRegistration = notificationService.registerNotificationListener(listener); - final DataModificationTransaction tx = dataService.beginTransaction(); - tx.putOperationalData(path, new TopologyBuilder().setKey(key).build()); + final ReadWriteTransaction tx = dataBroker.newReadWriteTransaction(); + tx.put(LogicalDatastoreType.OPERATIONAL, path, new TopologyBuilder().setKey(key).build()); try { - tx.commit().get(); + tx.submit().get(); } catch (InterruptedException | ExecutionException e) { LOG.warn("Initial topology export failed, continuing anyway", e); } @@ -87,8 +87,7 @@ public class FlowCapableTopologyProvider extends AbstractBindingAwareProvider im /** * Gets called during stop bundle * - * @param context - * The execution context of the bundle being stopped. + * @param context The execution context of the bundle being stopped. */ @Override public void stopImpl(final BundleContext context) { diff --git a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/OperationProcessor.java b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/OperationProcessor.java index d60c88032d..3800413eb1 100644 --- a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/OperationProcessor.java +++ b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/OperationProcessor.java @@ -7,30 +7,27 @@ */ package org.opendaylight.md.controller.topology.manager; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ExecutionException; import java.util.concurrent.LinkedBlockingQueue; - -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; -import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Preconditions; - final class OperationProcessor implements Runnable { private static final Logger LOG = LoggerFactory.getLogger(OperationProcessor.class); private static final int MAX_TRANSACTION_OPERATIONS = 100; private static final int OPERATION_QUEUE_DEPTH = 500; private final BlockingQueue queue = new LinkedBlockingQueue<>(OPERATION_QUEUE_DEPTH); - // FIXME: Flow capable topology exporter should use transaction chaining API - private final DataProviderService dataService; + private final DataBroker dataBroker; - OperationProcessor(final DataProviderService dataService) { - this.dataService = Preconditions.checkNotNull(dataService); + OperationProcessor(final DataBroker dataBroker) { + this.dataBroker = Preconditions.checkNotNull(dataBroker); } void enqueueOperation(final TopologyOperation task) { @@ -44,11 +41,11 @@ final class OperationProcessor implements Runnable { @Override public void run() { try { - for (;;) { + for (; ; ) { TopologyOperation op = queue.take(); LOG.debug("New operations available, starting transaction"); - final DataModificationTransaction tx = dataService.beginTransaction(); + final ReadWriteTransaction tx = dataBroker.newReadWriteTransaction(); int ops = 0; do { @@ -64,14 +61,18 @@ final class OperationProcessor implements Runnable { LOG.debug("Processed {} operations, submitting transaction", ops); - try { - final RpcResult s = tx.commit().get(); - if (!s.isSuccessful()) { - LOG.error("Topology export failed for Tx:{}", tx.getIdentifier()); + final CheckedFuture txResultFuture = tx.submit(); + Futures.addCallback(txResultFuture, new FutureCallback() { + @Override + public void onSuccess(Object o) { + LOG.debug("Topology export successful for tx :{}", tx.getIdentifier()); + } + + @Override + public void onFailure(Throwable throwable) { + LOG.error("Topology export transaction {} failed", tx.getIdentifier(), throwable.getCause()); } - } catch (ExecutionException e) { - LOG.error("Topology export transaction {} failed", tx.getIdentifier(), e.getCause()); - } + }); } } catch (InterruptedException e) { LOG.info("Interrupted processing, terminating", e); diff --git a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/TopologyOperation.java b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/TopologyOperation.java index 29d06beade..bbb8a74b03 100644 --- a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/TopologyOperation.java +++ b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/TopologyOperation.java @@ -7,7 +7,7 @@ */ package org.opendaylight.md.controller.topology.manager; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; /** * Internal interface for submitted operations. Implementations of this @@ -19,5 +19,5 @@ interface TopologyOperation { * * @param transaction Datastore transaction */ - void applyOperation(DataModificationTransaction transaction); + void applyOperation(ReadWriteTransaction transaction); } \ No newline at end of file diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronRouter.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronRouter.java index 2c10cca0c0..ae5aa0f7fb 100644 --- a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronRouter.java +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronRouter.java @@ -43,9 +43,18 @@ public class NeutronRouter extends ConfigurationObject implements Serializable, @XmlElement (name="tenant_id") String tenantID; - @XmlElement (name="external_gateway_info") + @XmlElement (name="external_gateway_info", nillable=true) NeutronRouter_NetworkReference externalGatewayInfo; + @XmlElement (name="distributed") + Boolean distributed; + + @XmlElement (name="gw_port_id", nillable=true) + String gatewayPortId; + + @XmlElement (name="routes") + List routes; + /* Holds a map of OpenStackRouterInterfaces by subnet UUID * used for internal mapping to DOVE */ @@ -112,6 +121,30 @@ public class NeutronRouter extends ConfigurationObject implements Serializable, this.externalGatewayInfo = externalGatewayInfo; } + public Boolean getDistributed() { + return distributed; + } + + public void setDistributed(Boolean distributed) { + this.distributed = distributed; + } + + public String getGatewayPortId() { + return gatewayPortId; + } + + public void setGatewayPortId(String gatewayPortId) { + this.gatewayPortId = gatewayPortId; + } + + public List getRoutes() { + return routes; + } + + public void setRoutes(List routes) { + this.routes = routes; + } + /** * This method copies selected fields from the object and returns them * as a new object, suitable for marshaling. @@ -121,7 +154,6 @@ public class NeutronRouter extends ConfigurationObject implements Serializable, * @return an OpenStackRouters object with only the selected fields * populated */ - public NeutronRouter extractFields(List fields) { NeutronRouter ans = new NeutronRouter(); Iterator i = fields.iterator(); @@ -145,6 +177,15 @@ public class NeutronRouter extends ConfigurationObject implements Serializable, if (s.equals("external_gateway_info")) { ans.setExternalGatewayInfo(this.getExternalGatewayInfo()); } + if (s.equals("distributed")) { + ans.setDistributed(this.getDistributed()); + } + if (s.equals("gw_port_id")) { + ans.setGatewayPortId(this.getGatewayPortId()); + } + if (s.equals("routes")){ + ans.setRoutes(this.getRoutes()); + } } return ans; } diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java index f93191220b..af7cfd18b9 100644 --- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java @@ -203,7 +203,7 @@ public class NeutronFloatingIPsNorthbound { // if floating IP is specified, make sure it can come from the network String floatingIP = singleton.getFloatingIPAddress(); if (floatingIP != null) { - if (externNetwork.getSubnets().size() > 1) + if (externNetwork.getSubnets().size() != 1) throw new BadRequestException("external network doesn't have a subnet"); NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0)); if (!externSubnet.isValidIP(floatingIP)) @@ -312,7 +312,7 @@ public class NeutronFloatingIPsNorthbound { if (!input.isSingleton()) throw new BadRequestException("only singleton requests allowed."); NeutronFloatingIP singleton = input.getSingleton(); - if (singleton.getID() != null) + if (singleton.getID() == null) throw new BadRequestException("singleton UUID doesn't exist."); NeutronNetwork externNetwork = networkInterface.getNetwork( @@ -321,7 +321,7 @@ public class NeutronFloatingIPsNorthbound { // if floating IP is specified, make sure it can come from the network String floatingIP = singleton.getFloatingIPAddress(); if (floatingIP != null) { - if (externNetwork.getSubnets().size() > 1) + if (externNetwork.getSubnets().size() != 1) throw new BadRequestException("external network doesn't have a subnet."); NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0)); if (!externSubnet.isValidIP(floatingIP))