From: Devin Avery Date: Mon, 18 Aug 2014 15:24:20 +0000 (+0000) Subject: Merge "Modifications to error handling in restconf" X-Git-Tag: release/helium~273 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=d771aa3f949bae84facc8db5abc2af5bdcca6fc9;hp=56d706d763660200815887a0f59f6c2a57a0237a;p=controller.git Merge "Modifications to error handling in restconf" --- diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index 66a403560e..c74e7ae410 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -1633,6 +1633,11 @@ binding-generator-impl ${yangtools.version} + + org.opendaylight.yangtools + binding-data-codec + ${yangtools.version} + org.opendaylight.yangtools binding-generator-spi 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/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 969ecc2cbe..d70bf46411 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -1165,6 +1165,10 @@ org.opendaylight.yangtools binding-generator-impl + + org.opendaylight.yangtools + binding-data-codec + org.opendaylight.yangtools binding-generator-spi diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java index c8a7f01e13..130c096deb 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java @@ -9,67 +9,89 @@ package org.opendaylight.controller.frm; import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicLong; -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** + * AbstractChangeListner implemented basic {@link AsyncDataChangeEvent} processing for + * flow node subDataObject (flows, groups and meters). * * @author Vaclav Demcak * */ public abstract class AbstractChangeListener implements DataChangeListener { + private final static Logger LOG = LoggerFactory.getLogger(AbstractChangeListener.class); + private final AtomicLong txNum = new AtomicLong(); private String transactionId; @Override - public void onDataChanged(DataChangeEvent, DataObject> changeEvent) { + public void onDataChanged(final AsyncDataChangeEvent, DataObject> changeEvent) { this.transactionId = this.newTransactionIdentifier().toString(); - + /* All DataObjects for create */ final Set, DataObject>> createdEntries = - changeEvent.getCreatedConfigurationData().entrySet(); - final Set, DataObject>> updatedEntries = - new HashSet, DataObject>>(); - + changeEvent.getCreatedData().entrySet(); + /* All DataObjects for updates - init HashSet */ + final Set, DataObject>> updatedEntries = new HashSet<>(); + /* Filtered DataObject for update processing only */ Set, DataObject>> updateConfigEntrySet = - changeEvent.getUpdatedConfigurationData().entrySet(); + changeEvent.getUpdatedData().entrySet(); updatedEntries.addAll(updateConfigEntrySet); updatedEntries.removeAll(createdEntries); - + /* All DataObjects for remove */ final Set> removeEntriesInstanceIdentifiers = - changeEvent.getRemovedConfigurationData(); - + changeEvent.getRemovedPaths(); + /* Create DataObject processing (send to device) */ for (final Entry, DataObject> createdEntry : createdEntries) { - InstanceIdentifier c_key = createdEntry.getKey(); - DataObject c_value = createdEntry.getValue(); - this.add(c_key, c_value); + InstanceIdentifier entryKey = createdEntry.getKey(); + DataObject entryValue = createdEntry.getValue(); + if (preconditionForChange(entryKey, entryValue, null)) { + this.add(entryKey, entryValue); + } } for (final Entry, DataObject> updatedEntrie : updatedEntries) { Map, DataObject> origConfigData = - changeEvent.getOriginalConfigurationData(); - - InstanceIdentifier u_key = updatedEntrie.getKey(); - final DataObject originalFlow = origConfigData.get(u_key); - final DataObject updatedFlow = updatedEntrie.getValue(); - this.update(u_key, originalFlow, updatedFlow); + changeEvent.getOriginalData(); + + InstanceIdentifier entryKey = updatedEntrie.getKey(); + final DataObject original = origConfigData.get(entryKey); + final DataObject updated = updatedEntrie.getValue(); + if (preconditionForChange(entryKey, original, updated)) { + this.update(entryKey, original, updated); + } } for (final InstanceIdentifier instanceId : removeEntriesInstanceIdentifiers) { Map, DataObject> origConfigData = - changeEvent.getOriginalConfigurationData(); + changeEvent.getOriginalData(); final DataObject removeValue = origConfigData.get(instanceId); - this.remove(instanceId, removeValue); + if (preconditionForChange(instanceId, removeValue, null)) { + this.remove(instanceId, removeValue); + } } } + /** + * Method returns generated transaction ID, which is unique for + * every transaction. ID is composite from prefix ("DOM") and unique number. + * + * @return String transactionID + */ public String getTransactionId() { return this.transactionId; } @@ -78,17 +100,74 @@ public abstract class AbstractChangeListener implements DataChangeListener { return "DOM-" + txNum.getAndIncrement(); } - protected abstract void validate() throws IllegalStateException; - - protected abstract void remove( + /** + * Method check all local preconditions for apply relevant changes. + * + * @param InstanceIdentifier identifier - the whole path to DataObject + * @param DataObject original - original DataObject (for update) + * or relevant DataObject (add/delete operations) + * @param DataObject update - changed DataObject (contain updates) + * or should be null for (add/delete operations) + * + * @return boolean - applicable + */ + protected abstract boolean preconditionForChange( final InstanceIdentifier identifier, + final DataObject original, final DataObject update); + + /** + * Method checks the node data path in DataStore/OPERATIONAL because + * without the Node Identifier in DataStore/OPERATIONAL, device + * is not connected and device pre-configuration is allowed only. + * + * @param InstanceIdentifier identifier - could be whole path to DataObject, + * but parent Node.class InstanceIdentifier is used for a check only + * + * @return boolean - is the Node available in DataStore/OPERATIONAL (is connected) + */ + protected boolean isNodeAvailable(final InstanceIdentifier identifier, + final ReadOnlyTransaction readTrans) { + final InstanceIdentifier nodeInstanceId = identifier.firstIdentifierOf(Node.class); + try { + return readTrans.read(LogicalDatastoreType.OPERATIONAL, nodeInstanceId).get().isPresent(); + } + catch (InterruptedException | ExecutionException e) { + LOG.error("Unexpected exception by reading Node ".concat(nodeInstanceId.toString()), e); + return false; + } + finally { + readTrans.close(); + } + } + + /** + * Method removes DataObject which is identified by InstanceIdentifier + * from device. + * + * @param InstanceIdentifier identifier - the whole path to DataObject + * @param DataObject remove - DataObject for removing + */ + protected abstract void remove(final InstanceIdentifier identifier, final DataObject remove); - protected abstract void update( - final InstanceIdentifier identifier, + /** + * Method updates the original DataObject to the update DataObject + * in device. Both are identified by same InstanceIdentifier + * + * @param InstanceIdentifier identifier - the whole path to DataObject + * @param DataObject original - original DataObject (for update) + * @param DataObject update - changed DataObject (contain updates) + */ + protected abstract void update(final InstanceIdentifier identifier, final DataObject original, final DataObject update); - protected abstract void add( - final InstanceIdentifier identifier, + /** + * Method adds the DataObject which is identified by InstanceIdentifier + * to device. + * + * @param InstanceIdentifier identifier - the whole path to new DataObject + * @param DataObject add - new DataObject + */ + protected abstract void add(final InstanceIdentifier identifier, final DataObject add); } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java index 2f986ea5bc..c75c644c00 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java @@ -10,52 +10,79 @@ package org.opendaylight.controller.frm; import org.opendaylight.controller.frm.flow.FlowProvider; import org.opendaylight.controller.frm.group.GroupProvider; import org.opendaylight.controller.frm.meter.MeterProvider; +import org.opendaylight.controller.frm.reconil.FlowNodeReconcilProvider; +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.data.DataProviderService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Forwarding Rules Manager Activator + * + * Activator manages all Providers ({@link FlowProvider}, {@link GroupProvider}, + * {@link MeterProvider} and the {@link FlowNodeReconcilProvider}). + * It registers all listeners (DataChangeEvent, ReconcilNotification) + * in the Session Initialization phase. + * + * @author Vaclav Demcak + * * + */ public class FRMActivator extends AbstractBindingAwareProvider { private final static Logger LOG = LoggerFactory.getLogger(FRMActivator.class); - private static FlowProvider flowProvider = new FlowProvider(); - private static GroupProvider groupProvider = new GroupProvider(); - private static MeterProvider meterProvider = new MeterProvider(); + private final FlowProvider flowProvider; + private final GroupProvider groupProvider; + private final MeterProvider meterProvider; + private final FlowNodeReconcilProvider flowNodeReconcilProvider; + + public FRMActivator() { + this.flowProvider = new FlowProvider(); + this.groupProvider = new GroupProvider(); + this.meterProvider = new MeterProvider(); + this.flowNodeReconcilProvider = new FlowNodeReconcilProvider(); + } @Override public void onSessionInitiated(final ProviderContext session) { - DataProviderService flowSalService = session.getSALService(DataProviderService.class); - FRMActivator.flowProvider.setDataService(flowSalService); - SalFlowService rpcFlowSalService = session.getRpcService(SalFlowService.class); - FRMActivator.flowProvider.setSalFlowService(rpcFlowSalService); - FRMActivator.flowProvider.start(); - DataProviderService groupSalService = session.getSALService(DataProviderService.class); - FRMActivator.groupProvider.setDataService(groupSalService); - SalGroupService rpcGroupSalService = session.getRpcService(SalGroupService.class); - FRMActivator.groupProvider.setSalGroupService(rpcGroupSalService); - FRMActivator.groupProvider.start(); - DataProviderService meterSalService = session.getSALService(DataProviderService.class); - FRMActivator.meterProvider.setDataService(meterSalService); - SalMeterService rpcMeterSalService = session.getRpcService(SalMeterService.class); - FRMActivator.meterProvider.setSalMeterService(rpcMeterSalService); - FRMActivator.meterProvider.start(); + LOG.info("FRMActivator initialization."); + /* Flow */ + try { + final DataBroker flowSalService = session.getSALService(DataBroker.class); + this.flowProvider.init(flowSalService); + this.flowProvider.start(session); + /* Group */ + final DataBroker groupSalService = session.getSALService(DataBroker.class); + this.groupProvider.init(groupSalService); + this.groupProvider.start(session); + /* Meter */ + final DataBroker meterSalService = session.getSALService(DataBroker.class); + this.meterProvider.init(meterSalService); + this.meterProvider.start(session); + /* FlowNode Reconciliation */ + final DataBroker dbs = session.getSALService(DataBroker.class); + this.flowNodeReconcilProvider.init(dbs); + this.flowNodeReconcilProvider.start(session); + + LOG.info("FRMActivator started successfully"); + } catch (Exception e) { + String errMsg = "Unexpected error by starting FRMActivator"; + LOG.error(errMsg, e); + throw new IllegalStateException(errMsg, e); + } } @Override protected void stopImpl(final BundleContext context) { try { - FRMActivator.flowProvider.close(); - FRMActivator.groupProvider.close(); - FRMActivator.meterProvider.close(); - } catch (Throwable e) { + this.flowProvider.close(); + this.groupProvider.close(); + this.meterProvider.close(); + this.flowNodeReconcilProvider.close(); + } catch (Exception e) { LOG.error("Unexpected error by stopping FRMActivator", e); - throw new RuntimeException(e); } } } \ No newline at end of file diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowCookieProducer.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowCookieProducer.java new file mode 100644 index 0000000000..d7b54e8380 --- /dev/null +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowCookieProducer.java @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2014 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.frm; + +import java.math.BigInteger; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.AtomicLongMap; + +/** + * forwardingrules-manager + * org.opendaylight.controller.frm + * + * Singleton FlowCookieProducer contains a FlowCookie generator which is generated unique + * flowCookie identifier for every flow in same Table. That could help with quick + * identification of flow statistic because DataStore/CONFIGURATION could contains + * a lot of flows with same flowCookie. So we are replacing original flowCookie + * with unique and we are building final FlowCookieMap in DataStore/OPERATIONAL + * + * @author Vaclav Demcak + * + * Created: Jun 13, 2014 + */ +public enum FlowCookieProducer { + + INSTANCE; + + /* Flow_Cookie_Key and Flow_Ids MapHolder */ + private static final AtomicLongMap> cookieKeys = AtomicLongMap.create(); + + /** + * Method returns the unique cookie for a node table. + * Flow Cookie Key signs List for a right flow statistic identification + * in the DataStore/operational. + * We need a List because system doesn't guarantee unique mapping + * from flow_cookie to flow_id. REST Operations doesn't used FRM yet, so + * cookie from user input could have a user input flow ID and an alien system ID + * which is generated by system. + * + * @param InstanceIdentifier tableIdentifier + * @return unique BigInteger flowCookie for a node table + */ + public BigInteger getNewCookie(final InstanceIdentifier
tableIdentifier) { + FlowCookieProducer.validationTableIdentifier(tableIdentifier); + if ( cookieKeys.containsKey(tableIdentifier)) { + /* new identifier always starts from ONE because + * ZERO is reserved for the NO_COOKIES flows */ + return BigInteger.valueOf(cookieKeys.addAndGet(tableIdentifier, 1L)); + } else { + return BigInteger.valueOf(cookieKeys.incrementAndGet(tableIdentifier)); + } + } + + /** + * Method cleans the node table flow_cookie_key for the disconnected Node. + * + * @param InstanceIdentifier
tableIdentifier + */ + public void clean(final InstanceIdentifier
tableIdentifier) { + FlowCookieProducer.validationTableIdentifier(tableIdentifier); + cookieKeys.remove(tableIdentifier); + } + + /* + * Help the TableIdentifer input validation method + */ + private static void validationTableIdentifier(final InstanceIdentifier
tableIdent) { + Preconditions.checkArgument(tableIdent != null, "Input validation exception: TableIdentifier can not be null !"); + } +} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java index b60424513f..c10b0da2ba 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java @@ -7,22 +7,21 @@ */ package org.opendaylight.controller.frm.flow; +import java.math.BigInteger; + import org.opendaylight.controller.frm.AbstractChangeListener; +import org.opendaylight.controller.frm.FlowCookieProducer; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; @@ -31,90 +30,97 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; + /** + * Flow Change Listener + * add, update and remove {@link Flow} processing from {@link org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent}. * * @author Vaclav Demcak * */ public class FlowChangeListener extends AbstractChangeListener { - private final static Logger LOG = LoggerFactory.getLogger(FlowChangeListener.class); + private static final Logger LOG = LoggerFactory.getLogger(FlowChangeListener.class); - private final SalFlowService salFlowService; - - public SalFlowService getSalFlowService() { - return this.salFlowService; - } + private final FlowProvider provider; - public FlowChangeListener(final SalFlowService manager) { - this.salFlowService = manager; + public FlowChangeListener (final FlowProvider provider) { + this.provider = Preconditions.checkNotNull(provider, "FlowProvider can not be null !"); } @Override - protected void validate() throws IllegalStateException { - FlowTransactionValidator.validate(this); - } + protected void remove(final InstanceIdentifier identifier, + final DataObject removeDataObj) { - @Override - protected void remove(InstanceIdentifier identifier, DataObject removeDataObj) { - if ((removeDataObj instanceof Flow)) { - - final Flow flow = ((Flow) removeDataObj); - final InstanceIdentifier
tableInstanceId = identifier.
firstIdentifierOf(Table.class); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final RemoveFlowInputBuilder builder = new RemoveFlowInputBuilder(flow); - - builder.setFlowRef(new FlowRef(identifier)); - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setFlowTable(new FlowTableRef(tableInstanceId)); - - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); - this.salFlowService.removeFlow((RemoveFlowInput) builder.build()); - LOG.debug("Transaction {} - Removed Flow has removed flow: {}", new Object[]{uri, removeDataObj}); - } + final Flow flow = ((Flow) removeDataObj); + final InstanceIdentifier
tableIdent = identifier.firstIdentifierOf(Table.class); + final InstanceIdentifier nodeIdent = identifier.firstIdentifierOf(Node.class); + final RemoveFlowInputBuilder builder = new RemoveFlowInputBuilder(flow); + + // use empty cookie mask in order to delete flow even with generated cookie + builder.setCookieMask(new FlowCookie(BigInteger.ZERO)); + + builder.setFlowRef(new FlowRef(identifier)); + builder.setNode(new NodeRef(nodeIdent)); + builder.setFlowTable(new FlowTableRef(tableIdent)); + + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); + this.provider.getSalFlowService().removeFlow(builder.build()); + LOG.debug("Transaction {} - Removed Flow has removed flow: {}", new Object[]{uri, removeDataObj}); } @Override - protected void update(InstanceIdentifier identifier, DataObject original, DataObject update) { - if (original instanceof Flow && update instanceof Flow) { + protected void update(final InstanceIdentifier identifier, + final DataObject original, final DataObject update) { + + final Flow originalFlow = ((Flow) original); + final Flow updatedFlow = ((Flow) update); + final InstanceIdentifier nodeIdent = identifier.firstIdentifierOf(Node.class); + final UpdateFlowInputBuilder builder = new UpdateFlowInputBuilder(); - final Flow originalFlow = ((Flow) original); - final Flow updatedFlow = ((Flow) update); - final InstanceIdentifier nodeInstanceId = identifier.firstIdentifierOf(Node.class); - final UpdateFlowInputBuilder builder = new UpdateFlowInputBuilder(); + builder.setNode(new NodeRef(nodeIdent)); + builder.setFlowRef(new FlowRef(identifier)); - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setFlowRef(new FlowRef(identifier)); + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); + builder.setUpdatedFlow((new UpdatedFlowBuilder(updatedFlow)).build()); + builder.setOriginalFlow((new OriginalFlowBuilder(originalFlow)).build()); - builder.setUpdatedFlow((UpdatedFlow) (new UpdatedFlowBuilder(updatedFlow)).build()); - builder.setOriginalFlow((OriginalFlow) (new OriginalFlowBuilder(originalFlow)).build()); + this.provider.getSalFlowService().updateFlow(builder.build()); + LOG.debug("Transaction {} - Update Flow has updated flow {} with {}", new Object[]{uri, original, update}); + } - this.salFlowService.updateFlow((UpdateFlowInput) builder.build()); - LOG.debug("Transaction {} - Update Flow has updated flow {} with {}", new Object[]{uri, original, update}); - } + @Override + protected void add(final InstanceIdentifier identifier, + final DataObject addDataObj) { + + final Flow flow = ((Flow) addDataObj); + final InstanceIdentifier
tableIdent = identifier.firstIdentifierOf(Table.class); + final NodeRef nodeRef = new NodeRef(identifier.firstIdentifierOf(Node.class)); + final FlowCookie flowCookie = new FlowCookie(FlowCookieProducer.INSTANCE.getNewCookie(tableIdent)); + final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow); + + builder.setNode(nodeRef); + builder.setFlowRef(new FlowRef(identifier)); + builder.setFlowTable(new FlowTableRef(tableIdent)); + builder.setCookie( flowCookie ); + + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); + this.provider.getSalFlowService().addFlow(builder.build()); + LOG.debug("Transaction {} - Add Flow has added flow: {}", new Object[]{uri, addDataObj}); } @Override - protected void add(InstanceIdentifier identifier, DataObject addDataObj) { - if ((addDataObj instanceof Flow)) { - - final Flow flow = ((Flow) addDataObj); - final InstanceIdentifier
tableInstanceId = identifier.
firstIdentifierOf(Table.class); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow); - - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setFlowRef(new FlowRef(identifier)); - builder.setFlowTable(new FlowTableRef(tableInstanceId)); - - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); - this.salFlowService.addFlow((AddFlowInput) builder.build()); - LOG.debug("Transaction {} - Add Flow has added flow: {}", new Object[]{uri, addDataObj}); - } + protected boolean preconditionForChange(final InstanceIdentifier identifier, + final DataObject dataObj, final DataObject update) { + + final ReadOnlyTransaction trans = this.provider.getDataService().newReadOnlyTransaction(); + return update != null + ? (dataObj instanceof Flow && update instanceof Flow && isNodeAvailable(identifier, trans)) + : (dataObj instanceof Flow && isNodeAvailable(identifier, trans)); } } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java index 33db529598..8c248fa264 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java @@ -7,9 +7,11 @@ */ package org.opendaylight.controller.frm.flow; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; 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.table.Flow; @@ -17,54 +19,89 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalF import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yangtools.concepts.ListenerRegistration; -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; + +/** + * Flow Provider registers the {@link FlowChangeListener} and it holds all needed + * services for {@link FlowChangeListener}. + * + * @author Vaclav Demcak + * + */ public class FlowProvider implements AutoCloseable { - private final static Logger LOG = LoggerFactory.getLogger(FlowProvider.class); + private static final Logger LOG = LoggerFactory.getLogger(FlowProvider.class); private SalFlowService salFlowService; - private DataProviderService dataService; + private DataBroker dataService; /* DataChangeListener */ - private FlowChangeListener flowDataChangeListener; - ListenerRegistration flowDataChangeListenerRegistration; + private DataChangeListener flowDataChangeListener; + private ListenerRegistration flowDataChangeListenerRegistration; + + /** + * Provider Initialization Phase. + * + * @param DataProviderService dataService + */ + public void init (final DataBroker dataService) { + LOG.info("FRM Flow Config Provider initialization."); + this.dataService = Preconditions.checkNotNull(dataService, "DataProviderService can not be null !"); + } + + /** + * Listener Registration Phase + * + * @param RpcConsumerRegistry rpcRegistry + */ + public void start(final RpcConsumerRegistry rpcRegistry) { + Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !"); + + this.salFlowService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalFlowService.class), + "RPC SalFlowService not found."); - public void start() { /* Build Path */ - InstanceIdentifierBuilder nodesBuilder = InstanceIdentifier. builder(Nodes.class); - InstanceIdentifierBuilder nodeChild = nodesBuilder. child(Node.class); - InstanceIdentifierBuilder augmentFlowCapNode = nodeChild. augmentation(FlowCapableNode.class); - InstanceIdentifierBuilder
tableChild = augmentFlowCapNode.
child(Table.class); - InstanceIdentifierBuilder flowChild = tableChild. child(Flow.class); - final InstanceIdentifier flowDataObjectPath = flowChild.toInstance(); + InstanceIdentifier flowIdentifier = InstanceIdentifier.create(Nodes.class) + .child(Node.class).augmentation(FlowCapableNode.class).child(Table.class).child(Flow.class); /* DataChangeListener registration */ - this.flowDataChangeListener = new FlowChangeListener(this.salFlowService); - this.flowDataChangeListenerRegistration = this.dataService.registerDataChangeListener(flowDataObjectPath, flowDataChangeListener); - LOG.info("Flow Config Provider started."); - } + this.flowDataChangeListener = new FlowChangeListener(FlowProvider.this); + this.flowDataChangeListenerRegistration = + this.dataService.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + flowIdentifier, flowDataChangeListener, DataChangeScope.SUBTREE); - protected DataModificationTransaction startChange() { - return this.dataService.beginTransaction(); + LOG.info("FRM Flow Config Provider started."); } @Override - public void close() throws Exception { - if(flowDataChangeListenerRegistration != null){ - flowDataChangeListenerRegistration.close(); + public void close() { + LOG.info("FRM Flow Config Provider stopped."); + if (flowDataChangeListenerRegistration != null) { + try { + flowDataChangeListenerRegistration.close(); + } catch (Exception e) { + String errMsg = "Error by stop FRM Flow Config Provider."; + LOG.error(errMsg, e); + throw new IllegalStateException(errMsg, e); + } finally { + flowDataChangeListenerRegistration = null; + } } } - public void setDataService(final DataProviderService dataService) { - this.dataService = dataService; + public DataChangeListener getFlowDataChangeListener() { + return flowDataChangeListener; + } + + public SalFlowService getSalFlowService() { + return salFlowService; } - public void setSalFlowService(final SalFlowService salFlowService) { - this.salFlowService = salFlowService; + public DataBroker getDataService() { + return dataService; } } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java deleted file mode 100644 index 9cd42466a6..0000000000 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2014 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.frm.flow; - -public class FlowTransactionValidator { - - public static void validate(FlowChangeListener transaction) throws IllegalStateException { - // NOOP - } -} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java index 54f12bfdcf..9b03eaad8c 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java @@ -8,17 +8,12 @@ package org.opendaylight.controller.frm.group; import org.opendaylight.controller.frm.AbstractChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroup; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroup; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; @@ -29,85 +24,88 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; + /** + * Group Change Listener + * add, update and remove {@link Group} processing from {@link org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent}. * * @author Vaclav Demcak * */ public class GroupChangeListener extends AbstractChangeListener { - private final static Logger LOG = LoggerFactory.getLogger(GroupChangeListener.class); - - private final SalGroupService salGroupService; + private static final Logger LOG = LoggerFactory.getLogger(GroupChangeListener.class); - public SalGroupService getSalGroupService() { - return this.salGroupService; - } + private final GroupProvider provider; - public GroupChangeListener(final SalGroupService manager) { - this.salGroupService = manager; + public GroupChangeListener(final GroupProvider provider) { + this.provider = Preconditions.checkNotNull(provider, "GroupProvider can not be null !"); } @Override - protected void validate() throws IllegalStateException { - GroupTransactionValidator.validate(this); + protected void remove(final InstanceIdentifier identifier, + final DataObject removeDataObj) { + + final Group group = ((Group) removeDataObj); + final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); + final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group); + + builder.setNode(new NodeRef(nodeInstanceId)); + builder.setGroupRef(new GroupRef(identifier)); + + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); + this.provider.getSalGroupService().removeGroup(builder.build()); + LOG.debug("Transaction {} - Remove Group has removed group: {}", new Object[]{uri, removeDataObj}); } @Override - protected void remove(InstanceIdentifier identifier, DataObject removeDataObj) { - if ((removeDataObj instanceof Group)) { + protected void update(final InstanceIdentifier identifier, + final DataObject original, final DataObject update) { - final Group group = ((Group) removeDataObj); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group); + final Group originalGroup = ((Group) original); + final Group updatedGroup = ((Group) update); + final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); + final UpdateGroupInputBuilder builder = new UpdateGroupInputBuilder(); - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setGroupRef(new GroupRef(identifier)); + builder.setNode(new NodeRef(nodeInstanceId)); + builder.setGroupRef(new GroupRef(identifier)); - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); - this.salGroupService.removeGroup((RemoveGroupInput) builder.build()); - LOG.debug("Transaction {} - Remove Group has removed group: {}", new Object[]{uri, removeDataObj}); - } - } + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); - @Override - protected void update(InstanceIdentifier identifier, DataObject original, DataObject update) { - if (original instanceof Group && update instanceof Group) { + builder.setUpdatedGroup((new UpdatedGroupBuilder(updatedGroup)).build()); + builder.setOriginalGroup((new OriginalGroupBuilder(originalGroup)).build()); - final Group originalGroup = ((Group) original); - final Group updatedGroup = ((Group) update); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final UpdateGroupInputBuilder builder = new UpdateGroupInputBuilder(); + this.provider.getSalGroupService().updateGroup(builder.build()); + LOG.debug("Transaction {} - Update Group has updated group {} with group {}", new Object[]{uri, original, update}); + } - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setGroupRef(new GroupRef(identifier)); + @Override + protected void add(final InstanceIdentifier identifier, + final DataObject addDataObj) { - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); + final Group group = ((Group) addDataObj); + final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); + final AddGroupInputBuilder builder = new AddGroupInputBuilder(group); - builder.setUpdatedGroup((UpdatedGroup) (new UpdatedGroupBuilder(updatedGroup)).build()); - builder.setOriginalGroup((OriginalGroup) (new OriginalGroupBuilder(originalGroup)).build()); + builder.setNode(new NodeRef(nodeInstanceId)); + builder.setGroupRef(new GroupRef(identifier)); - this.salGroupService.updateGroup((UpdateGroupInput) builder.build()); - LOG.debug("Transaction {} - Update Group has updated group {} with group {}", new Object[]{uri, original, update}); - } + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); + this.provider.getSalGroupService().addGroup(builder.build()); + LOG.debug("Transaction {} - Add Group has added group: {}", new Object[]{uri, addDataObj}); } @Override - protected void add(InstanceIdentifier identifier, DataObject addDataObj) { - if ((addDataObj instanceof Group)) { - final Group group = ((Group) addDataObj); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final AddGroupInputBuilder builder = new AddGroupInputBuilder(group); - - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setGroupRef(new GroupRef(identifier)); - - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); - this.salGroupService.addGroup((AddGroupInput) builder.build()); - LOG.debug("Transaction {} - Add Group has added group: {}", new Object[]{uri, addDataObj}); - } + protected boolean preconditionForChange(final InstanceIdentifier identifier, + final DataObject dataObj, final DataObject update) { + + final ReadOnlyTransaction trans = this.provider.getDataService().newReadOnlyTransaction(); + return update != null + ? (dataObj instanceof Group && update instanceof Group && isNodeAvailable(identifier, trans)) + : (dataObj instanceof Group && isNodeAvailable(identifier, trans)); } } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java index 9f2806e929..a999242bc0 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java @@ -7,61 +7,99 @@ */ package org.opendaylight.controller.frm.group; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yangtools.concepts.ListenerRegistration; -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; + +/** + * Group Provider registers the {@link GroupChangeListener} and it holds all needed + * services for {@link GroupChangeListener}. + * + * @author Vaclav Demcak + * + */ public class GroupProvider implements AutoCloseable { - private final static Logger LOG = LoggerFactory.getLogger(GroupProvider.class); + private static final Logger LOG = LoggerFactory.getLogger(GroupProvider.class); private SalGroupService salGroupService; - private DataProviderService dataService; + private DataBroker dataService; /* DataChangeListener */ - private GroupChangeListener groupDataChangeListener; - ListenerRegistration groupDataChangeListenerRegistration; + private DataChangeListener groupDataChangeListener; + private ListenerRegistration groupDataChangeListenerRegistration; + + /** + * Provider Initialization Phase. + * + * @param DataProviderService dataService + */ + public void init (final DataBroker dataService) { + LOG.info("FRM Group Config Provider initialization."); + this.dataService = Preconditions.checkNotNull(dataService, "DataService can not be null !"); + } + + /** + * Listener Registration Phase + * + * @param RpcConsumerRegistry rpcRegistry + */ + public void start(final RpcConsumerRegistry rpcRegistry) { + Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !"); + + this.salGroupService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalGroupService.class), + "RPC SalGroupService not found."); - public void start() { /* Build Path */ - InstanceIdentifierBuilder nodesBuilder = InstanceIdentifier. builder(Nodes.class); - InstanceIdentifierBuilder nodeChild = nodesBuilder. child(Node.class); - InstanceIdentifierBuilder augmentFlowCapNode = nodeChild. augmentation(FlowCapableNode.class); - InstanceIdentifierBuilder groupChild = augmentFlowCapNode. child(Group.class); - final InstanceIdentifier groupDataObjectPath = groupChild.toInstance(); + InstanceIdentifier groupIdentifier = InstanceIdentifier.create(Nodes.class) + .child(Node.class).augmentation(FlowCapableNode.class).child(Group.class); /* DataChangeListener registration */ - this.groupDataChangeListener = new GroupChangeListener(this.salGroupService); - this.groupDataChangeListenerRegistration = this.dataService.registerDataChangeListener(groupDataObjectPath, groupDataChangeListener); - LOG.info("Group Config Provider started."); - } + this.groupDataChangeListener = new GroupChangeListener(GroupProvider.this); + this.groupDataChangeListenerRegistration = this.dataService.registerDataChangeListener( + LogicalDatastoreType.CONFIGURATION, groupIdentifier, groupDataChangeListener, DataChangeScope.SUBTREE); - protected DataModificationTransaction startChange() { - return this.dataService.beginTransaction(); + LOG.info("FRM Group Config Provider started."); } - public void close() throws Exception { - if(groupDataChangeListenerRegistration != null){ - groupDataChangeListenerRegistration.close(); + @Override + public void close() { + LOG.info("FRM Group Config Provider stopped."); + if (groupDataChangeListenerRegistration != null) { + try { + groupDataChangeListenerRegistration.close(); + } catch (Exception e) { + String errMsg = "Error by stop FRM Group Config Provider."; + LOG.error(errMsg, e); + throw new IllegalStateException(errMsg, e); + } finally { + groupDataChangeListenerRegistration = null; + } } } - public void setDataService(final DataProviderService dataService) { - this.dataService = dataService; + public DataChangeListener getGroupDataChangeListener() { + return groupDataChangeListener; + } + + public SalGroupService getSalGroupService() { + return salGroupService; } - public void setSalGroupService(final SalGroupService salGroupService) { - this.salGroupService = salGroupService; + public DataBroker getDataService() { + return dataService; } } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransactionValidator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransactionValidator.java deleted file mode 100644 index 88eea0db34..0000000000 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransactionValidator.java +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2014 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.frm.group; - -public class GroupTransactionValidator { - - public static void validate(GroupChangeListener transaction) throws IllegalStateException { - // NOOP - } -} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java index 48d5257978..a2def8490f 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java @@ -8,19 +8,14 @@ package org.opendaylight.controller.frm.meter; import org.opendaylight.controller.frm.AbstractChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeter; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeterBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeter; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef; @@ -29,86 +24,89 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; + /** + * Meter Change Listener + * add, update and remove {@link Meter} processing from {@link org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent}. * * @author Vaclav Demcak * */ public class MeterChangeListener extends AbstractChangeListener { - private final static Logger LOG = LoggerFactory.getLogger(MeterChangeListener.class); - - private final SalMeterService salMeterService; - - public SalMeterService getSalMeterService() { - return this.salMeterService; - } + private static final Logger LOG = LoggerFactory.getLogger(MeterChangeListener.class); - public MeterChangeListener(final SalMeterService manager) { - this.salMeterService = manager; - } + private final MeterProvider provider; - @Override - protected void validate() throws IllegalStateException { - MeterTransactionValidator.validate(this); + public MeterChangeListener (final MeterProvider provider) { + this.provider = Preconditions.checkNotNull(provider, "MeterProvider can not be null !"); } @Override - protected void remove(InstanceIdentifier identifier, DataObject removeDataObj) { - if ((removeDataObj instanceof Meter)) { + protected void remove(final InstanceIdentifier identifier, + final DataObject removeDataObj) { - final Meter meter = ((Meter) removeDataObj); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(meter); + final Meter meter = ((Meter) removeDataObj); + final InstanceIdentifier nodeIdent = identifier.firstIdentifierOf(Node.class); + final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(meter); - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setMeterRef(new MeterRef(identifier)); + builder.setNode(new NodeRef(nodeIdent)); + builder.setMeterRef(new MeterRef(identifier)); - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); - this.salMeterService.removeMeter((RemoveMeterInput) builder.build()); - LOG.debug("Transaction {} - Remove Meter has removed meter: {}", new Object[]{uri, removeDataObj}); - } + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); + this.provider.getSalMeterService().removeMeter(builder.build()); + LOG.debug("Transaction {} - Remove Meter has removed meter: {}", new Object[]{uri, removeDataObj}); } @Override - protected void update(InstanceIdentifier identifier, DataObject original, DataObject update) { - if (original instanceof Meter && update instanceof Meter) { + protected void update(final InstanceIdentifier identifier, + final DataObject original, final DataObject update) { - final Meter originalMeter = ((Meter) original); - final Meter updatedMeter = ((Meter) update); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder(); + final Meter originalMeter = ((Meter) original); + final Meter updatedMeter = ((Meter) update); + final InstanceIdentifier nodeInstanceId = identifier.firstIdentifierOf(Node.class); + final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder(); - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setMeterRef(new MeterRef(identifier)); + builder.setNode(new NodeRef(nodeInstanceId)); + builder.setMeterRef(new MeterRef(identifier)); - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); - builder.setUpdatedMeter((UpdatedMeter) (new UpdatedMeterBuilder(updatedMeter)).build()); - builder.setOriginalMeter((OriginalMeter) (new OriginalMeterBuilder(originalMeter)).build()); + builder.setUpdatedMeter((new UpdatedMeterBuilder(updatedMeter)).build()); + builder.setOriginalMeter((new OriginalMeterBuilder(originalMeter)).build()); + + this.provider.getSalMeterService().updateMeter(builder.build()); + LOG.debug("Transaction {} - Update Meter has updated meter {} with {}", new Object[]{uri, original, update}); - this.salMeterService.updateMeter((UpdateMeterInput) builder.build()); - LOG.debug("Transaction {} - Update Meter has updated meter {} with {}", new Object[]{uri, original, update}); - } } @Override - protected void add(InstanceIdentifier identifier, DataObject addDataObj) { - if ((addDataObj instanceof Meter)) { + protected void add(final InstanceIdentifier identifier, + final DataObject addDataObj) { + + final Meter meter = ((Meter) addDataObj); + final InstanceIdentifier nodeInstanceId = identifier.firstIdentifierOf(Node.class); + final AddMeterInputBuilder builder = new AddMeterInputBuilder(meter); - final Meter meter = ((Meter) addDataObj); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final AddMeterInputBuilder builder = new AddMeterInputBuilder(meter); + builder.setNode(new NodeRef(nodeInstanceId)); + builder.setMeterRef(new MeterRef(identifier)); - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setMeterRef(new MeterRef(identifier)); + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); + this.provider.getSalMeterService().addMeter(builder.build()); + LOG.debug("Transaction {} - Add Meter has added meter: {}", new Object[]{uri, addDataObj}); + } + + @Override + protected boolean preconditionForChange(final InstanceIdentifier identifier, + final DataObject dataObj, final DataObject update) { - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); - this.salMeterService.addMeter((AddMeterInput) builder.build()); - LOG.debug("Transaction {} - Add Meter has added meter: {}", new Object[]{uri, addDataObj}); - } + final ReadOnlyTransaction trans = this.provider.getDataService().newReadOnlyTransaction(); + return update != null + ? (dataObj instanceof Meter && update instanceof Meter && isNodeAvailable(identifier, trans)) + : (dataObj instanceof Meter && isNodeAvailable(identifier, trans)); } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java index 8596c3fec6..44de7af495 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java @@ -7,61 +7,99 @@ */ package org.opendaylight.controller.frm.meter; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService; import org.opendaylight.yangtools.concepts.ListenerRegistration; -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; + +/** + * Meter Provider registers the {@link MeterChangeListener} and it holds all needed + * services for {@link MeterChangeListener}. + * + * @author Vaclav Demcak + * + */ public class MeterProvider implements AutoCloseable { - private final static Logger LOG = LoggerFactory.getLogger(MeterProvider.class); + private static final Logger LOG = LoggerFactory.getLogger(MeterProvider.class); - private DataProviderService dataService; private SalMeterService salMeterService; + private DataBroker dataService; /* DataChangeListener */ - private MeterChangeListener meterDataChangeListener; - ListenerRegistration meterDataChangeListenerRegistration; + private DataChangeListener meterDataChangeListener; + private ListenerRegistration meterDataChangeListenerRegistration; + + /** + * Provider Initialization Phase. + * + * @param DataProviderService dataService + */ + public void init(final DataBroker dataService) { + LOG.info("FRM Meter Config Provider initialization."); + this.dataService = Preconditions.checkNotNull(dataService, "DataProviderService can not be null !"); + } + + /** + * Listener Registration Phase + * + * @param RpcConsumerRegistry rpcRegistry + */ + public void start(final RpcConsumerRegistry rpcRegistry) { + Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !"); + this.salMeterService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalMeterService.class), + "RPC SalMeterService not found."); - public void start() { /* Build Path */ - InstanceIdentifierBuilder nodesBuilder = InstanceIdentifier. builder(Nodes.class); - InstanceIdentifierBuilder nodeChild = nodesBuilder. child(Node.class); - InstanceIdentifierBuilder augmentFlowCapNode = nodeChild. augmentation(FlowCapableNode.class); - InstanceIdentifierBuilder meterChild = augmentFlowCapNode. child(Meter.class); - final InstanceIdentifier meterDataObjectPath = meterChild.toInstance(); + InstanceIdentifier meterIdentifier = InstanceIdentifier.create(Nodes.class) + .child(Node.class).augmentation(FlowCapableNode.class).child(Meter.class); /* DataChangeListener registration */ - this.meterDataChangeListener = new MeterChangeListener(this.salMeterService); - this.meterDataChangeListenerRegistration = this.dataService.registerDataChangeListener(meterDataObjectPath, meterDataChangeListener); - LOG.info("Meter Config Provider started."); - } + this.meterDataChangeListener = new MeterChangeListener(MeterProvider.this); + this.meterDataChangeListenerRegistration = + this.dataService.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + meterIdentifier, meterDataChangeListener, DataChangeScope.SUBTREE); - protected DataModificationTransaction startChange() { - return this.dataService.beginTransaction(); + LOG.info("FRM Meter Config Provider started."); } - public void close() throws Exception { - if(meterDataChangeListenerRegistration != null){ - meterDataChangeListenerRegistration.close(); + @Override + public void close() { + LOG.info("FRM Meter Config Provider stopped."); + if (meterDataChangeListenerRegistration != null) { + try { + meterDataChangeListenerRegistration.close(); + } catch (Exception e) { + String errMsg = "Error by stop FRM Meter Config Provider."; + LOG.error(errMsg, e); + throw new IllegalStateException(errMsg, e); + } finally { + meterDataChangeListenerRegistration = null; + } } } - public void setDataService(final DataProviderService dataService) { - this.dataService = dataService; + public DataChangeListener getMeterDataChangeListener() { + return meterDataChangeListener; + } + + public DataBroker getDataService() { + return dataService; } - public void setSalMeterService(final SalMeterService salMeterService) { - this.salMeterService = salMeterService; + public SalMeterService getSalMeterService() { + return salMeterService; } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransactionValidator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransactionValidator.java deleted file mode 100644 index c8fba23b93..0000000000 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransactionValidator.java +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2014 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.frm.meter; - -public class MeterTransactionValidator { - - public static void validate(MeterChangeListener transaction) throws IllegalStateException { - // NOOP - } -} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilListener.java new file mode 100644 index 0000000000..eb5ae4a9d3 --- /dev/null +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilListener.java @@ -0,0 +1,185 @@ +/** + * Copyright (c) 2014 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.frm.reconil; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.frm.AbstractChangeListener; +import org.opendaylight.controller.frm.FlowCookieProducer; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +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.meters.Meter; +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.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.ListenableFuture; + +/** + * forwardingrules-manager + * org.opendaylight.controller.frm + * + * FlowNode Reconciliation Listener + * Reconciliation for a new FlowNode + * Remove CookieMapKey for removed FlowNode + * + * @author Vaclav Demcak + * + * Created: Jun 13, 2014 + */ +public class FlowNodeReconcilListener extends AbstractChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconcilListener.class); + + private final FlowNodeReconcilProvider provider; + + public FlowNodeReconcilListener(final FlowNodeReconcilProvider provider) { + this.provider = Preconditions.checkNotNull(provider, "Flow Node Reconcil Provider can not be null!"); + } + + @Override + public void onDataChanged(AsyncDataChangeEvent, DataObject> changeEvent) { + /* FlowCapableNode DataObjects for reconciliation */ + final Set, DataObject>> createdEntries = + changeEvent.getCreatedData().entrySet(); + /* FlowCapableNode DataObjects for clean FlowCookieHolder */ + final Set> removeEntriesInstanceIdentifiers = + changeEvent.getRemovedPaths(); + for (final Entry, DataObject> createdEntry : createdEntries) { + InstanceIdentifier entryKey = createdEntry.getKey(); + DataObject entryValue = createdEntry.getValue(); + if (preconditionForChange(entryKey, entryValue, null)) { + this.add(entryKey, entryValue); + } + } + for (final InstanceIdentifier instanceId : removeEntriesInstanceIdentifiers) { + Map, DataObject> origConfigData = + changeEvent.getOriginalData(); + final DataObject removeValue = origConfigData.get(instanceId); + if (preconditionForChange(instanceId, removeValue, null)) { + this.remove(instanceId, removeValue); + } + } + } + + @Override + /* Cleaning FlowCookieManager holder for all node tables */ + protected void remove(final InstanceIdentifier identifier, + final DataObject removeDataObj) { + + final InstanceIdentifier flowNodeIdent = + identifier.firstIdentifierOf(FlowCapableNode.class); + final FlowCapableNode flowNode = ((FlowCapableNode) removeDataObj); + + for (Table flowTable : flowNode.getTable()) { + final InstanceIdentifier
tableIdent = + flowNodeIdent.child(Table.class, flowTable.getKey()); + FlowCookieProducer.INSTANCE.clean(tableIdent); + } + } + + @Override + /* Reconciliation by connect new FlowCapableNode */ + protected void add(final InstanceIdentifier identifier, + final DataObject addDataObj) { + + final InstanceIdentifier flowNodeIdent = + identifier.firstIdentifierOf(FlowCapableNode.class); + final Optional flowCapNode = this.readFlowCapableNode(flowNodeIdent); + + if (flowCapNode.isPresent()) { + final InstanceIdentifier nodeIdent = identifier.firstIdentifierOf(Node.class); + final NodeRef nodeRef = new NodeRef(nodeIdent); + /* Groups - have to be first */ + for (Group group : flowCapNode.get().getGroup()) { + final GroupRef groupRef = new GroupRef(flowNodeIdent.child(Group.class, group.getKey())); + final AddGroupInputBuilder groupBuilder = new AddGroupInputBuilder(group); + groupBuilder.setGroupRef(groupRef); + groupBuilder.setNode(nodeRef); + this.provider.getSalGroupService().addGroup(groupBuilder.build()); + } + /* Meters */ + for (Meter meter : flowCapNode.get().getMeter()) { + final MeterRef meterRef = new MeterRef(flowNodeIdent.child(Meter.class, meter.getKey())); + final AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder(meter); + meterBuilder.setMeterRef(meterRef); + meterBuilder.setNode(nodeRef); + this.provider.getSalMeterService().addMeter(meterBuilder.build()); + } + /* Flows */ + for (Table flowTable : flowCapNode.get().getTable()) { + final InstanceIdentifier
tableIdent = flowNodeIdent.child(Table.class, flowTable.getKey()); + for (Flow flow : flowTable.getFlow()) { + final FlowCookie flowCookie = new FlowCookie(FlowCookieProducer.INSTANCE.getNewCookie(tableIdent)); + final FlowRef flowRef = new FlowRef(tableIdent.child(Flow.class, flow.getKey())); + final FlowTableRef flowTableRef = new FlowTableRef(tableIdent); + final AddFlowInputBuilder flowBuilder = new AddFlowInputBuilder(flow); + flowBuilder.setCookie(flowCookie); + flowBuilder.setNode(nodeRef); + flowBuilder.setFlowTable(flowTableRef); + flowBuilder.setFlowRef(flowRef); + this.provider.getSalFlowService().addFlow(flowBuilder.build()); + } + } + } + } + + @Override + protected void update(final InstanceIdentifier identifier, + final DataObject original, DataObject update) { + // NOOP - Listener is registered for DataChangeScope.BASE only + } + + @Override + protected boolean preconditionForChange(final InstanceIdentifier identifier, + final DataObject dataObj, final DataObject update) { + return (dataObj instanceof FlowCapableNode); + } + + private Optional readFlowCapableNode(final InstanceIdentifier flowNodeIdent) { + ReadOnlyTransaction readTrans = this.provider.getDataService().newReadOnlyTransaction(); + try { + ListenableFuture> confFlowNode = + readTrans.read(LogicalDatastoreType.CONFIGURATION, flowNodeIdent); + if (confFlowNode.get().isPresent()) { + return Optional. of(confFlowNode.get().get()); + } else { + return Optional.absent(); + } + } + catch (InterruptedException | ExecutionException e) { + LOG.error("Unexpected exception by reading flow ".concat(flowNodeIdent.toString()), e); + return Optional.absent(); + } + finally { + readTrans.close(); + } + } +} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilProvider.java new file mode 100644 index 0000000000..ad970d6043 --- /dev/null +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilProvider.java @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2014 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.frm.reconil; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +/** + * forwardingrules-manager + * org.opendaylight.controller.frm + * + * FlowNode Reconciliation Provider registers the FlowNodeReconilListener + * and it holds all needed services for FlowNodeReconcilListener. + * + * @author Vaclav Demcak + * + * Created: Jun 13, 2014 + */ +public class FlowNodeReconcilProvider implements AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconcilProvider.class); + + private SalFlowService salFlowService; + private SalMeterService salMeterService; + private SalGroupService salGroupService; + private DataBroker dataService; + + /* DataChangeListener */ + private DataChangeListener flowNodeReconcilListener; + private ListenerRegistration flowNodeReconcilListenerRegistration; + + public void init (final DataBroker dataService) { + LOG.info("FRM Flow Node Config Reconcil Provider initialization."); + + this.dataService = Preconditions.checkNotNull(dataService, "DataProviderService can not be null !"); + } + + public void start( final RpcConsumerRegistry rpcRegistry ) { + Preconditions.checkArgument(rpcRegistry != null, "RpcConcumerRegistry can not be null !"); + + this.salFlowService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalFlowService.class), + "RPC SalFlowService not found."); + this.salMeterService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalMeterService.class), + "RPC SalMeterService not found."); + this.salGroupService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalGroupService.class), + "RPC SalGroupService not found."); + + /* Build Path */ + InstanceIdentifier flowCapableNodeIdent = + InstanceIdentifier.create(Nodes.class).child(Node.class).augmentation(FlowCapableNode.class); + + /* ReconcilNotificationListener registration */ + this.flowNodeReconcilListener = new FlowNodeReconcilListener(FlowNodeReconcilProvider.this); + this.flowNodeReconcilListenerRegistration = this.dataService.registerDataChangeListener( + LogicalDatastoreType.OPERATIONAL, flowCapableNodeIdent, flowNodeReconcilListener, DataChangeScope.BASE); + LOG.info("FRM Flow Node Config Reconcil Provider started."); + } + + @Override + public void close() { + LOG.info("FRM Flow Node Config Reconcil Provider stopped."); + if (flowNodeReconcilListenerRegistration != null) { + try { + flowNodeReconcilListenerRegistration.close(); + } catch (Exception e) { + String errMsg = "Error by stop FRM Flow Node Config Reconcil Provider."; + LOG.error(errMsg, e); + throw new IllegalStateException(errMsg, e); + } finally { + flowNodeReconcilListenerRegistration = null; + } + } + } + + public DataChangeListener getFlowNodeReconcilListener() { + return flowNodeReconcilListener; + } + + public DataBroker getDataService() { + return dataService; + } + + public SalFlowService getSalFlowService() { + return salFlowService; + } + + public SalMeterService getSalMeterService() { + return salMeterService; + } + + public SalGroupService getSalGroupService() { + return salGroupService; + } +} 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/model/model-flow-service/src/main/yang/flow-node-inventory.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang index 65362a1790..605cb9004a 100644 --- a/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang @@ -229,4 +229,16 @@ module flow-node-inventory { uses flow-node-connector; } + augment "/inv:nodes/inv:node/table" { + ext:augment-identifier "flow-cookie-mapping"; + list flow-cookie-map { + key "cookie"; + leaf cookie { + type flow:flow-cookie; + } + leaf-list flow-ids { + type flow-id; + } + } + } } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBrokerAwareActivator.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBrokerAwareActivator.java index b62e4529f3..bd78c584ee 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBrokerAwareActivator.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBrokerAwareActivator.java @@ -39,14 +39,20 @@ public abstract class AbstractBrokerAwareActivator implements BundleActivator { @Override public void modifiedService(ServiceReference reference, BindingAwareBroker service) { - // TODO Auto-generated method stub - + removedService(reference, service); + addingService(reference); } @Override public void removedService(ServiceReference reference, BindingAwareBroker service) { - // TODO Auto-generated method stub + broker = context.getService(reference); + mdActivationPool.execute(new Runnable() { + @Override + public void run() { + onBrokerRemoved(broker, context); + } + }); } }; @@ -117,6 +123,6 @@ public abstract class AbstractBrokerAwareActivator implements BundleActivator { protected abstract void onBrokerAvailable(BindingAwareBroker broker, BundleContext context); protected void onBrokerRemoved(BindingAwareBroker broker, BundleContext context) { - + stopImpl(context); } } 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/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/pom.xml index 674c5bf5a5..38ec5f5ac2 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/pom.xml @@ -200,6 +200,9 @@ + + + diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorConstants.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorConstants.java index 1f1a0f5cc6..da0d62897a 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorConstants.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorConstants.java @@ -16,4 +16,5 @@ public class ActorConstants { public static final String RPC_BROKER_PATH= "/user/rpc/rpc-broker"; public static final String RPC_REGISTRY_PATH = "/user/rpc/rpc-registry"; + public static final String RPC_MANAGER_PATH = "/user/rpc"; } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcImplementation.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcImplementation.java index d384144f4f..02e2d12015 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcImplementation.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcImplementation.java @@ -4,7 +4,6 @@ import akka.actor.ActorRef; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import org.opendaylight.controller.remote.rpc.messages.ErrorResponse; -import org.opendaylight.controller.remote.rpc.messages.InvokeRoutedRpc; import org.opendaylight.controller.remote.rpc.messages.InvokeRpc; import org.opendaylight.controller.remote.rpc.messages.RpcResponse; import org.opendaylight.controller.remote.rpc.utils.ActorUtil; @@ -36,7 +35,7 @@ public class RemoteRpcImplementation implements RpcImplementation, @Override public ListenableFuture> invokeRpc(QName rpc, YangInstanceIdentifier identifier, CompositeNode input) { - InvokeRoutedRpc rpcMsg = new InvokeRoutedRpc(rpc, identifier, input); + InvokeRpc rpcMsg = new InvokeRpc(rpc, identifier, input); return executeMsg(rpcMsg); } @@ -49,7 +48,7 @@ public class RemoteRpcImplementation implements RpcImplementation, @Override public ListenableFuture> invokeRpc(QName rpc, CompositeNode input) { - InvokeRpc rpcMsg = new InvokeRpc(rpc, input); + InvokeRpc rpcMsg = new InvokeRpc(rpc, null, input); return executeMsg(rpcMsg); } @@ -57,7 +56,7 @@ public class RemoteRpcImplementation implements RpcImplementation, ListenableFuture> listenableFuture = null; try { - Object response = ActorUtil.executeLocalOperation(rpcBroker, rpcMsg, ActorUtil.ASK_DURATION, ActorUtil.AWAIT_DURATION); + Object response = ActorUtil.executeOperation(rpcBroker, rpcMsg, ActorUtil.ASK_DURATION, ActorUtil.AWAIT_DURATION); if(response instanceof RpcResponse) { RpcResponse rpcResponse = (RpcResponse) response; @@ -74,7 +73,7 @@ public class RemoteRpcImplementation implements RpcImplementation, } } catch (Exception e) { - LOG.error("Error occurred while invoking RPC actor {}", e.toString()); + LOG.error("Error occurred while invoking RPC actor {}", e); final RpcResultBuilder failed = RpcResultBuilder.failed(); failed.withError(null, null, e.getMessage(), null, null, e.getCause()); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProvider.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProvider.java index ac50b8fe5b..d088f2284d 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProvider.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProvider.java @@ -12,8 +12,6 @@ package org.opendaylight.controller.remote.rpc; import akka.actor.ActorRef; import akka.actor.ActorSystem; import org.opendaylight.controller.remote.rpc.messages.UpdateSchemaContext; -import org.opendaylight.controller.remote.rpc.registry.ClusterWrapper; -import org.opendaylight.controller.remote.rpc.registry.ClusterWrapperImpl; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; @@ -64,11 +62,10 @@ public class RemoteRpcProvider implements AutoCloseable, Provider, SchemaContext private void start() { LOG.info("Starting all rpc listeners and actors."); // Create actor to handle and sync routing table in cluster - ClusterWrapper clusterWrapper = new ClusterWrapperImpl(actorSystem); SchemaService schemaService = brokerSession.getService(SchemaService.class); schemaContext = schemaService.getGlobalContext(); - rpcManager = actorSystem.actorOf(RpcManager.props(clusterWrapper, schemaContext, brokerSession, rpcProvisionRegistry), ActorConstants.RPC_MANAGER); + rpcManager = actorSystem.actorOf(RpcManager.props(schemaContext, brokerSession, rpcProvisionRegistry), ActorConstants.RPC_MANAGER); LOG.debug("Rpc actors are created."); } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RoutedRpcListener.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RoutedRpcListener.java index a6eeac0270..98cf6a329f 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RoutedRpcListener.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RoutedRpcListener.java @@ -13,15 +13,14 @@ import akka.actor.ActorRef; import com.google.common.base.Preconditions; import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; -import org.opendaylight.controller.remote.rpc.messages.AddRoutedRpc; -import org.opendaylight.controller.remote.rpc.messages.RemoveRoutedRpc; -import org.opendaylight.controller.remote.rpc.utils.ActorUtil; +import org.opendaylight.controller.remote.rpc.registry.RpcRegistry; import org.opendaylight.controller.sal.connector.api.RpcRouter; import org.opendaylight.controller.sal.core.api.RpcRoutingContext; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -29,23 +28,24 @@ import java.util.Set; public class RoutedRpcListener implements RouteChangeListener{ private static final Logger LOG = LoggerFactory.getLogger(RoutedRpcListener.class); private final ActorRef rpcRegistry; - private final String actorPath; - public RoutedRpcListener(ActorRef rpcRegistry, String actorPath) { + public RoutedRpcListener(ActorRef rpcRegistry) { Preconditions.checkNotNull(rpcRegistry, "rpc registry actor should not be null"); - Preconditions.checkNotNull(actorPath, "actor path of rpc broker on current node should not be null"); this.rpcRegistry = rpcRegistry; - this.actorPath = actorPath; } @Override public void onRouteChange(RouteChange routeChange) { Map> announcements = routeChange.getAnnouncements(); - announce(getRouteIdentifiers(announcements)); + if(announcements != null && announcements.size() > 0){ + announce(getRouteIdentifiers(announcements)); + } Map> removals = routeChange.getRemovals(); - remove(getRouteIdentifiers(removals)); + if(removals != null && removals.size() > 0 ) { + remove(getRouteIdentifiers(removals)); + } } /** @@ -54,13 +54,8 @@ public class RoutedRpcListener implements RouteChangeListener> announcements) { LOG.debug("Announcing [{}]", announcements); - AddRoutedRpc addRpcMsg = new AddRoutedRpc(announcements, actorPath); - try { - ActorUtil.executeLocalOperation(rpcRegistry, addRpcMsg, ActorUtil.LOCAL_ASK_DURATION, ActorUtil.LOCAL_AWAIT_DURATION); - } catch (Exception e) { - // Just logging it because Akka API throws this exception - LOG.error(e.toString()); - } + RpcRegistry.Messages.AddOrUpdateRoutes addRpcMsg = new RpcRegistry.Messages.AddOrUpdateRoutes(new ArrayList<>(announcements)); + rpcRegistry.tell(addRpcMsg, ActorRef.noSender()); } /** @@ -69,13 +64,8 @@ public class RoutedRpcListener implements RouteChangeListener> removals){ LOG.debug("Removing [{}]", removals); - RemoveRoutedRpc removeRpcMsg = new RemoveRoutedRpc(removals, actorPath); - try { - ActorUtil.executeLocalOperation(rpcRegistry, removeRpcMsg, ActorUtil.LOCAL_ASK_DURATION, ActorUtil.LOCAL_AWAIT_DURATION); - } catch (Exception e) { - // Just logging it because Akka API throws this exception - LOG.error(e.toString()); - } + RpcRegistry.Messages.RemoveRoutes removeRpcMsg = new RpcRegistry.Messages.RemoveRoutes(new ArrayList<>(removals)); + rpcRegistry.tell(removeRpcMsg, ActorRef.noSender()); } /** diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcBroker.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcBroker.java index 26e8e960e3..611618f1f6 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcBroker.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcBroker.java @@ -11,17 +11,17 @@ package org.opendaylight.controller.remote.rpc; import akka.actor.ActorRef; import akka.actor.Props; import akka.japi.Creator; +import akka.japi.Pair; import org.opendaylight.controller.remote.rpc.messages.ErrorResponse; import org.opendaylight.controller.remote.rpc.messages.ExecuteRpc; -import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpc; -import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpcReply; -import org.opendaylight.controller.remote.rpc.messages.GetRpc; -import org.opendaylight.controller.remote.rpc.messages.GetRpcReply; -import org.opendaylight.controller.remote.rpc.messages.InvokeRoutedRpc; import org.opendaylight.controller.remote.rpc.messages.InvokeRpc; import org.opendaylight.controller.remote.rpc.messages.RpcResponse; +import org.opendaylight.controller.remote.rpc.utils.LatestEntryRoutingLogic; +import org.opendaylight.controller.remote.rpc.registry.RpcRegistry; import org.opendaylight.controller.remote.rpc.utils.ActorUtil; +import org.opendaylight.controller.remote.rpc.utils.RoutingLogic; import org.opendaylight.controller.remote.rpc.utils.XmlUtils; +import org.opendaylight.controller.sal.connector.api.RpcRouter; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @@ -29,6 +29,7 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; import java.util.concurrent.Future; /** @@ -59,81 +60,57 @@ public class RpcBroker extends AbstractUntypedActor { } @Override protected void handleReceive(Object message) throws Exception { - if(message instanceof InvokeRoutedRpc) { - invokeRemoteRoutedRpc((InvokeRoutedRpc) message); - } else if(message instanceof InvokeRpc) { + if(message instanceof InvokeRpc) { invokeRemoteRpc((InvokeRpc) message); } else if(message instanceof ExecuteRpc) { executeRpc((ExecuteRpc) message); } } - private void invokeRemoteRoutedRpc(InvokeRoutedRpc msg) { - // Look up the remote actor to execute rpc - LOG.debug("Looking up the remote actor for route {}", msg); - try { - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, msg.getRpc(), msg.getIdentifier()); - GetRoutedRpc routedRpcMsg = new GetRoutedRpc(routeId); - GetRoutedRpcReply rpcReply = (GetRoutedRpcReply) ActorUtil.executeLocalOperation(rpcRegistry, routedRpcMsg, ActorUtil.LOCAL_ASK_DURATION, ActorUtil.LOCAL_AWAIT_DURATION); - - String remoteActorPath = rpcReply.getRoutePath(); - if(remoteActorPath == null) { - LOG.debug("No remote actor found for rpc execution."); - - getSender().tell(new ErrorResponse( - new IllegalStateException("No remote actor found for rpc execution.")), self()); - } else { - - ExecuteRpc executeMsg = new ExecuteRpc(XmlUtils.inputCompositeNodeToXml(msg.getInput(), schemaContext), msg.getRpc()); - - Object operationRes = ActorUtil.executeRemoteOperation(this.context().actorSelection(remoteActorPath), - executeMsg, ActorUtil.REMOTE_ASK_DURATION, ActorUtil.REMOTE_AWAIT_DURATION); - - getSender().tell(operationRes, self()); - } - } catch (Exception e) { - LOG.error(e.toString()); - getSender().tell(new ErrorResponse(e), self()); - } - } - private void invokeRemoteRpc(InvokeRpc msg) { // Look up the remote actor to execute rpc LOG.debug("Looking up the remote actor for route {}", msg); try { - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, msg.getRpc(), null); - GetRpc rpcMsg = new GetRpc(routeId); - GetRpcReply rpcReply = (GetRpcReply)ActorUtil.executeLocalOperation(rpcRegistry, rpcMsg, ActorUtil.LOCAL_ASK_DURATION, ActorUtil.LOCAL_AWAIT_DURATION); - String remoteActorPath = rpcReply.getRoutePath(); + // Find router + RpcRouter.RouteIdentifier routeId = new RouteIdentifierImpl(null, msg.getRpc(), msg.getIdentifier()); + RpcRegistry.Messages.FindRouters rpcMsg = new RpcRegistry.Messages.FindRouters(routeId); + RpcRegistry.Messages.FindRoutersReply rpcReply = + (RpcRegistry.Messages.FindRoutersReply) ActorUtil.executeOperation(rpcRegistry, rpcMsg, ActorUtil.LOCAL_ASK_DURATION, ActorUtil.LOCAL_AWAIT_DURATION); + + List> actorRefList = rpcReply.getRouterWithUpdateTime(); - if(remoteActorPath == null) { + if(actorRefList == null || actorRefList.isEmpty()) { LOG.debug("No remote actor found for rpc {{}}.", msg.getRpc()); getSender().tell(new ErrorResponse( - new IllegalStateException("No remote actor found for rpc execution of : " + msg.getRpc())), self()); + new IllegalStateException("No remote actor found for rpc execution of : " + msg.getRpc())), self()); } else { + RoutingLogic logic = new LatestEntryRoutingLogic(actorRefList); ExecuteRpc executeMsg = new ExecuteRpc(XmlUtils.inputCompositeNodeToXml(msg.getInput(), schemaContext), msg.getRpc()); - Object operationRes = ActorUtil.executeRemoteOperation(this.context().actorSelection(remoteActorPath), + Object operationRes = ActorUtil.executeOperation(logic.select(), executeMsg, ActorUtil.REMOTE_ASK_DURATION, ActorUtil.REMOTE_AWAIT_DURATION); getSender().tell(operationRes, self()); } } catch (Exception e) { - LOG.error(e.toString()); + LOG.error("invokeRemoteRpc: {}", e); getSender().tell(new ErrorResponse(e), self()); } } + + private void executeRpc(ExecuteRpc msg) { LOG.debug("Executing rpc for rpc {}", msg.getRpc()); try { - Future> rpc = brokerSession.rpc(msg.getRpc(), XmlUtils.inputXmlToCompositeNode(msg.getRpc(), msg.getInputCompositeNode(), schemaContext)); + Future> rpc = brokerSession.rpc(msg.getRpc(), + XmlUtils.inputXmlToCompositeNode(msg.getRpc(), msg.getInputCompositeNode(), schemaContext)); RpcResult rpcResult = rpc != null ? rpc.get():null; CompositeNode result = rpcResult != null ? rpcResult.getResult() : null; getSender().tell(new RpcResponse(XmlUtils.outputCompositeNodeToXml(result, schemaContext)), self()); } catch (Exception e) { - LOG.error(e.toString()); + LOG.error("executeRpc: {}", e); getSender().tell(new ErrorResponse(e), self()); } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcListener.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcListener.java index f614990669..dee98521ae 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcListener.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcListener.java @@ -10,50 +10,42 @@ package org.opendaylight.controller.remote.rpc; import akka.actor.ActorRef; -import org.opendaylight.controller.remote.rpc.messages.AddRpc; -import org.opendaylight.controller.remote.rpc.messages.RemoveRpc; -import org.opendaylight.controller.remote.rpc.utils.ActorUtil; +import org.opendaylight.controller.remote.rpc.registry.RpcRegistry; +import org.opendaylight.controller.sal.connector.api.RpcRouter; import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; import org.opendaylight.yangtools.yang.common.QName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.List; + public class RpcListener implements RpcRegistrationListener{ private static final Logger LOG = LoggerFactory.getLogger(RpcListener.class); private final ActorRef rpcRegistry; - private final String actorPath; - public RpcListener(ActorRef rpcRegistry, String actorPath) { + public RpcListener(ActorRef rpcRegistry) { this.rpcRegistry = rpcRegistry; - this.actorPath = actorPath; } @Override public void onRpcImplementationAdded(QName rpc) { LOG.debug("Adding registration for [{}]", rpc); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, rpc, null); - AddRpc addRpcMsg = new AddRpc(routeId, actorPath); - try { - ActorUtil.executeLocalOperation(rpcRegistry, addRpcMsg, ActorUtil.LOCAL_ASK_DURATION, ActorUtil.LOCAL_AWAIT_DURATION); - LOG.debug("Route added [{}-{}]", routeId, this.actorPath); - } catch (Exception e) { - // Just logging it because Akka API throws this exception - LOG.error(e.toString()); - } - + RpcRouter.RouteIdentifier routeId = new RouteIdentifierImpl(null, rpc, null); + List> routeIds = new ArrayList<>(); + routeIds.add(routeId); + RpcRegistry.Messages.AddOrUpdateRoutes addRpcMsg = new RpcRegistry.Messages.AddOrUpdateRoutes(routeIds); + rpcRegistry.tell(addRpcMsg, ActorRef.noSender()); } @Override public void onRpcImplementationRemoved(QName rpc) { LOG.debug("Removing registration for [{}]", rpc); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, rpc, null); - RemoveRpc removeRpcMsg = new RemoveRpc(routeId); - try { - ActorUtil.executeLocalOperation(rpcRegistry, removeRpcMsg, ActorUtil.LOCAL_ASK_DURATION, ActorUtil.LOCAL_AWAIT_DURATION); - } catch (Exception e) { - // Just logging it because Akka API throws this exception - LOG.error(e.toString()); - } + RpcRouter.RouteIdentifier routeId = new RouteIdentifierImpl(null, rpc, null); + List> routeIds = new ArrayList<>(); + routeIds.add(routeId); + RpcRegistry.Messages.RemoveRoutes removeRpcMsg = new RpcRegistry.Messages.RemoveRoutes(routeIds); + rpcRegistry.tell(removeRpcMsg, ActorRef.noSender()); } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcManager.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcManager.java index 514a2f141d..96f2472428 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcManager.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcManager.java @@ -16,8 +16,7 @@ import akka.actor.SupervisorStrategy; import akka.japi.Creator; import akka.japi.Function; import org.opendaylight.controller.remote.rpc.messages.UpdateSchemaContext; -import org.opendaylight.controller.remote.rpc.registry.ClusterWrapper; -import org.opendaylight.controller.remote.rpc.registry.RpcRegistryOld; +import org.opendaylight.controller.remote.rpc.registry.RpcRegistry; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.yangtools.yang.common.QName; @@ -38,7 +37,6 @@ public class RpcManager extends AbstractUntypedActor { private static final Logger LOG = LoggerFactory.getLogger(RpcManager.class); private SchemaContext schemaContext; - private final ClusterWrapper clusterWrapper; private ActorRef rpcBroker; private ActorRef rpcRegistry; private final Broker.ProviderSession brokerSession; @@ -47,9 +45,8 @@ public class RpcManager extends AbstractUntypedActor { private RemoteRpcImplementation rpcImplementation; private final RpcProvisionRegistry rpcProvisionRegistry; - private RpcManager(ClusterWrapper clusterWrapper, SchemaContext schemaContext, + private RpcManager(SchemaContext schemaContext, Broker.ProviderSession brokerSession, RpcProvisionRegistry rpcProvisionRegistry) { - this.clusterWrapper = clusterWrapper; this.schemaContext = schemaContext; this.brokerSession = brokerSession; this.rpcProvisionRegistry = rpcProvisionRegistry; @@ -59,12 +56,12 @@ public class RpcManager extends AbstractUntypedActor { } - public static Props props(final ClusterWrapper clusterWrapper, final SchemaContext schemaContext, + public static Props props(final SchemaContext schemaContext, final Broker.ProviderSession brokerSession, final RpcProvisionRegistry rpcProvisionRegistry) { return Props.create(new Creator() { @Override public RpcManager create() throws Exception { - return new RpcManager(clusterWrapper, schemaContext, brokerSession, rpcProvisionRegistry); + return new RpcManager(schemaContext, brokerSession, rpcProvisionRegistry); } }); } @@ -72,16 +69,19 @@ public class RpcManager extends AbstractUntypedActor { private void createRpcActors() { LOG.debug("Create rpc registry and broker actors"); - rpcRegistry = getContext().actorOf(RpcRegistryOld.props(clusterWrapper), ActorConstants.RPC_REGISTRY); + + rpcRegistry = getContext().actorOf(Props.create(RpcRegistry.class), ActorConstants.RPC_REGISTRY); + rpcBroker = getContext().actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext), ActorConstants.RPC_BROKER); + RpcRegistry.Messages.SetLocalRouter localRouter = new RpcRegistry.Messages.SetLocalRouter(rpcBroker); + rpcRegistry.tell(localRouter, self()); } private void startListeners() { LOG.debug("Registers rpc listeners"); - String rpcBrokerPath = clusterWrapper.getAddress().toString() + ActorConstants.RPC_BROKER_PATH; - rpcListener = new RpcListener(rpcRegistry, rpcBrokerPath); - routeChangeListener = new RoutedRpcListener(rpcRegistry, rpcBrokerPath); + rpcListener = new RpcListener(rpcRegistry); + routeChangeListener = new RoutedRpcListener(rpcRegistry); rpcImplementation = new RemoteRpcImplementation(rpcBroker, schemaContext); brokerSession.addRpcRegistrationListener(rpcListener); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/AddRoutedRpc.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/AddRoutedRpc.java deleted file mode 100644 index fd1af2b33c..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/AddRoutedRpc.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.messages; - -import com.google.common.base.Preconditions; -import org.opendaylight.controller.sal.connector.api.RpcRouter; - -import java.io.Serializable; -import java.util.Set; - -public class AddRoutedRpc implements Serializable { - - private final Set> announcements; - private final String actorPath; - - public AddRoutedRpc(final Set> announcements, final String actorPath) { - Preconditions.checkNotNull(announcements, "Route identifier should not be null"); - Preconditions.checkNotNull(actorPath, "Actor path should not be null"); - - this.announcements = announcements; - this.actorPath = actorPath; - } - - public Set> getAnnouncements() { - return announcements; - } - - public String getActorPath() { - return actorPath; - } -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/AddRpc.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/AddRpc.java deleted file mode 100644 index 7eaa8f0618..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/AddRpc.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.messages; - -import com.google.common.base.Preconditions; -import org.opendaylight.controller.remote.rpc.RouteIdentifierImpl; - -import java.io.Serializable; - -public class AddRpc implements Serializable { - - private final RouteIdentifierImpl routeId; - private final String actorPath; - - public AddRpc(final RouteIdentifierImpl routeId, final String actorPath) { - Preconditions.checkNotNull(routeId, "Route identifier should not be null"); - Preconditions.checkNotNull(actorPath, "Actor path should not be null"); - - this.routeId = routeId; - this.actorPath = actorPath; - } - - public RouteIdentifierImpl getRouteId() { - return routeId; - } - - public String getActorPath() { - return actorPath; - } -} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/GetRoutedRpc.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/GetRoutedRpc.java deleted file mode 100644 index e8d2262182..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/GetRoutedRpc.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.messages; - - -import com.google.common.base.Preconditions; -import org.opendaylight.controller.remote.rpc.RouteIdentifierImpl; - -import java.io.Serializable; - -public class GetRoutedRpc implements Serializable { - - private final RouteIdentifierImpl routeId; - - public GetRoutedRpc(final RouteIdentifierImpl routeId) { - Preconditions.checkNotNull(routeId, "route id should not be null"); - this.routeId = routeId; - } - - public RouteIdentifierImpl getRouteId() { - return routeId; - } -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/GetRoutedRpcReply.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/GetRoutedRpcReply.java deleted file mode 100644 index d426662192..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/GetRoutedRpcReply.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.opendaylight.controller.remote.rpc.messages; - -/* - * Copyright (c) 2014 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 - */ - -import java.io.Serializable; - -public class GetRoutedRpcReply implements Serializable { - - private final String routePath; - - public GetRoutedRpcReply(final String routePath) { - this.routePath = routePath; - } - - public String getRoutePath() { - return routePath; - } -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/GetRpc.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/GetRpc.java deleted file mode 100644 index c1d4240dca..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/GetRpc.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.messages; - -import com.google.common.base.Preconditions; -import org.opendaylight.controller.remote.rpc.RouteIdentifierImpl; - -import java.io.Serializable; - -public class GetRpc implements Serializable { - - private final RouteIdentifierImpl routeId; - - public GetRpc(final RouteIdentifierImpl routeId) { - Preconditions.checkNotNull(routeId, "Route Id should not be null"); - this.routeId = routeId; - } - - public RouteIdentifierImpl getRouteId() { - return routeId; - } -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/GetRpcReply.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/GetRpcReply.java deleted file mode 100644 index aaf089d16f..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/GetRpcReply.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.opendaylight.controller.remote.rpc.messages; - -/* - * Copyright (c) 2014 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 - */ - -import java.io.Serializable; - -public class GetRpcReply implements Serializable { - - private final String routePath; - - public GetRpcReply(final String routePath) { - this.routePath = routePath; - } - - public String getRoutePath() { - return routePath; - } -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/InvokeRoutedRpc.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/InvokeRoutedRpc.java deleted file mode 100644 index fd73144e1d..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/InvokeRoutedRpc.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.messages; - -import com.google.common.base.Preconditions; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; - -import java.io.Serializable; - -public class InvokeRoutedRpc implements Serializable { - - private final QName rpc; - private final YangInstanceIdentifier identifier; - private final CompositeNode input; - - public InvokeRoutedRpc(final QName rpc, final YangInstanceIdentifier identifier, final CompositeNode input) { - Preconditions.checkNotNull(rpc, "rpc qname should not be null"); - Preconditions.checkNotNull(identifier, "instance identifier of routed rpc should not be null"); - Preconditions.checkNotNull(input, "rpc input should not be null"); - - this.rpc = rpc; - this.identifier = identifier; - this.input = input; - } - - public QName getRpc() { - return rpc; - } - - public YangInstanceIdentifier getIdentifier() { - return identifier; - } - - public CompositeNode getInput() { - return input; - } -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/InvokeRpc.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/InvokeRpc.java index 94b7fe4024..59d09fc41b 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/InvokeRpc.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/InvokeRpc.java @@ -10,19 +10,22 @@ package org.opendaylight.controller.remote.rpc.messages; import com.google.common.base.Preconditions; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import java.io.Serializable; public class InvokeRpc implements Serializable { private final QName rpc; + private final YangInstanceIdentifier identifier; private final CompositeNode input; - public InvokeRpc(final QName rpc, final CompositeNode input) { + public InvokeRpc(final QName rpc, final YangInstanceIdentifier identifier, final CompositeNode input) { Preconditions.checkNotNull(rpc, "rpc qname should not be null"); Preconditions.checkNotNull(input, "rpc input should not be null"); this.rpc = rpc; + this.identifier = identifier; this.input = input; } @@ -30,6 +33,10 @@ public class InvokeRpc implements Serializable { return rpc; } + public YangInstanceIdentifier getIdentifier() { + return identifier; + } + public CompositeNode getInput() { return input; } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/RemoveRoutedRpc.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/RemoveRoutedRpc.java deleted file mode 100644 index b560b8c8c0..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/RemoveRoutedRpc.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.messages; - -import com.google.common.base.Preconditions; -import org.opendaylight.controller.sal.connector.api.RpcRouter; - -import java.io.Serializable; -import java.util.Set; - -public class RemoveRoutedRpc implements Serializable { - - private final Set> announcements; - private final String actorPath; - - public RemoveRoutedRpc(final Set> announcements, final String actorPath) { - Preconditions.checkNotNull(announcements, "Route identifier should not be null"); - Preconditions.checkNotNull(actorPath, "Actor path should not be null"); - - this.announcements = announcements; - this.actorPath = actorPath; - } - - public Set> getAnnouncements() { - return announcements; - } - - public String getActorPath() { - return actorPath; - } -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/RemoveRpc.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/RemoveRpc.java deleted file mode 100644 index 289334fccc..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/RemoveRpc.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.messages; - -import com.google.common.base.Preconditions; -import org.opendaylight.controller.remote.rpc.RouteIdentifierImpl; - -import java.io.Serializable; - -public class RemoveRpc implements Serializable { - - private final RouteIdentifierImpl routeId; - - public RemoveRpc(final RouteIdentifierImpl routeId) { - Preconditions.checkNotNull(routeId, "Route Id should not be null"); - - this.routeId = routeId; - } - - public RouteIdentifierImpl getRouteId() { - return routeId; - } -} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/RoutingTableData.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/RoutingTableData.java deleted file mode 100644 index c57a258426..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/RoutingTableData.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.messages; - -import org.opendaylight.controller.sal.connector.api.RpcRouter; - -import java.io.Serializable; -import java.util.LinkedHashSet; -import java.util.Map; - -public class RoutingTableData implements Serializable { - private final Map, String> rpcMap; - private final Map, LinkedHashSet> routedRpcMap; - - public RoutingTableData(final Map, String> rpcMap, - final Map, LinkedHashSet> routedRpcMap) { - this.rpcMap = rpcMap; - this.routedRpcMap = routedRpcMap; - } - - public Map, String> getRpcMap() { - return rpcMap; - } - - public Map, LinkedHashSet> getRoutedRpcMap() { - return routedRpcMap; - } -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/ClusterWrapper.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/ClusterWrapper.java deleted file mode 100644 index 4ddc2bee85..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/ClusterWrapper.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.registry; - - -import akka.actor.Address; -import akka.cluster.ClusterEvent; - -public interface ClusterWrapper { - - ClusterEvent.CurrentClusterState getState(); - - Address getAddress(); -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/ClusterWrapperImpl.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/ClusterWrapperImpl.java deleted file mode 100644 index 89603a134c..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/ClusterWrapperImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.registry; - - -import akka.actor.ActorSystem; -import akka.actor.Address; -import akka.cluster.Cluster; -import akka.cluster.ClusterEvent; - - -public class ClusterWrapperImpl implements ClusterWrapper{ - - private Cluster cluster; - - public ClusterWrapperImpl(ActorSystem actorSystem) { - cluster = Cluster.get(actorSystem); - } - - @Override - public ClusterEvent.CurrentClusterState getState() { - return cluster.state(); - } - - @Override - public Address getAddress() { - return cluster.selfAddress(); - } -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RoutingTableOld.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RoutingTableOld.java deleted file mode 100644 index 5951776f2c..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RoutingTableOld.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.registry; - -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableSet; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -public class RoutingTableOld { - - private final Logger LOG = LoggerFactory.getLogger(RoutingTableOld.class); - - private ConcurrentMap globalRpcMap = new ConcurrentHashMap<>(); - private ConcurrentMap> routedRpcMap = new ConcurrentHashMap<>(); - - public ConcurrentMap getGlobalRpcMap() { - return globalRpcMap; - } - - public ConcurrentMap> getRoutedRpcMap() { - return routedRpcMap; - } - - public R getGlobalRoute(final I routeId) { - Preconditions.checkNotNull(routeId, "getGlobalRoute: routeId cannot be null!"); - return globalRpcMap.get(routeId); - } - - public void addGlobalRoute(final I routeId, final R route) { - Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!"); - Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!"); - LOG.debug("addGlobalRoute: adding a new route with id[{}] and value [{}]", routeId, route); - if(globalRpcMap.putIfAbsent(routeId, route) != null) { - LOG.debug("A route already exist for route id [{}] ", routeId); - } - } - - public void removeGlobalRoute(final I routeId) { - Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!"); - LOG.debug("removeGlobalRoute: removing a new route with id [{}]", routeId); - globalRpcMap.remove(routeId); - } - - public Set getRoutedRpc(final I routeId) { - Preconditions.checkNotNull(routeId, "getRoutes: routeId cannot be null!"); - Set routes = routedRpcMap.get(routeId); - - if (routes == null) { - return Collections.emptySet(); - } - - return ImmutableSet.copyOf(routes); - } - - public R getLastAddedRoutedRpc(final I routeId) { - - Set routes = getRoutedRpc(routeId); - - if (routes.isEmpty()) { - return null; - } - - R route = null; - Iterator iter = routes.iterator(); - while (iter.hasNext()) { - route = iter.next(); - } - - return route; - } - - public void addRoutedRpc(final I routeId, final R route) { - Preconditions.checkNotNull(routeId, "addRoute: routeId cannot be null"); - Preconditions.checkNotNull(route, "addRoute: route cannot be null"); - LOG.debug("addRoute: adding a route with k/v [{}/{}]", routeId, route); - threadSafeAdd(routeId, route); - } - - public void addRoutedRpcs(final Set routeIds, final R route) { - Preconditions.checkNotNull(routeIds, "addRoutes: routeIds must not be null"); - for (I routeId : routeIds){ - addRoutedRpc(routeId, route); - } - } - - public void removeRoute(final I routeId, final R route) { - Preconditions.checkNotNull(routeId, "removeRoute: routeId cannot be null!"); - Preconditions.checkNotNull(route, "removeRoute: route cannot be null!"); - - LinkedHashSet routes = routedRpcMap.get(routeId); - if (routes == null) { - return; - } - LOG.debug("removeRoute: removing a new route with k/v [{}/{}]", routeId, route); - threadSafeRemove(routeId, route); - } - - public void removeRoutes(final Set routeIds, final R route) { - Preconditions.checkNotNull(routeIds, "removeRoutes: routeIds must not be null"); - for (I routeId : routeIds){ - removeRoute(routeId, route); - } - } - - /** - * This method guarantees that no 2 thread over write each other's changes. - * Just so that we dont end up in infinite loop, it tries for 100 times then throw - */ - private void threadSafeAdd(final I routeId, final R route) { - - for (int i=0;i<100;i++){ - - LinkedHashSet updatedRoutes = new LinkedHashSet<>(); - updatedRoutes.add(route); - LinkedHashSet oldRoutes = routedRpcMap.putIfAbsent(routeId, updatedRoutes); - if (oldRoutes == null) { - return; - } - - updatedRoutes = new LinkedHashSet<>(oldRoutes); - updatedRoutes.add(route); - - if (routedRpcMap.replace(routeId, oldRoutes, updatedRoutes)) { - return; - } - } - //the method did not already return means it failed to add route in 100 attempts - throw new IllegalStateException("Failed to add route [" + routeId + "]"); - } - - /** - * This method guarantees that no 2 thread over write each other's changes. - * Just so that we dont end up in infinite loop, it tries for 100 times then throw - */ - private void threadSafeRemove(final I routeId, final R route) { - LinkedHashSet updatedRoutes = null; - for (int i=0;i<100;i++){ - LinkedHashSet oldRoutes = routedRpcMap.get(routeId); - - // if route to be deleted is the only entry in the set then remove routeId from the cache - if ((oldRoutes.size() == 1) && oldRoutes.contains(route)){ - routedRpcMap.remove(routeId); - return; - } - - // if there are multiple routes for this routeId, remove the route to be deleted only from the set. - updatedRoutes = new LinkedHashSet<>(oldRoutes); - updatedRoutes.remove(route); - if (routedRpcMap.replace(routeId, oldRoutes, updatedRoutes)) { - return; - } - - } - //the method did not already return means it failed to remove route in 100 attempts - throw new IllegalStateException("Failed to remove route [" + routeId + "]"); - } -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryOld.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryOld.java deleted file mode 100644 index 96c8802ce6..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryOld.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.registry; - -import akka.actor.ActorSelection; -import akka.actor.Address; -import akka.actor.Props; -import akka.cluster.ClusterEvent; -import akka.cluster.Member; -import akka.japi.Creator; -import org.opendaylight.controller.remote.rpc.AbstractUntypedActor; -import org.opendaylight.controller.remote.rpc.ActorConstants; -import org.opendaylight.controller.remote.rpc.messages.AddRoutedRpc; -import org.opendaylight.controller.remote.rpc.messages.AddRpc; -import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpc; -import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpcReply; -import org.opendaylight.controller.remote.rpc.messages.GetRpc; -import org.opendaylight.controller.remote.rpc.messages.GetRpcReply; -import org.opendaylight.controller.remote.rpc.messages.RemoveRoutedRpc; -import org.opendaylight.controller.remote.rpc.messages.RemoveRpc; -import org.opendaylight.controller.remote.rpc.messages.RoutingTableData; -import org.opendaylight.controller.sal.connector.api.RpcRouter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import scala.collection.JavaConversions; - -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -/** - * This Actor maintains the routing table state and sync it with other nodes in the cluster. - * - * A scheduler runs after an interval of time, which pick a random member from the cluster - * and send the current state of routing table to the member. - * - * when a message of routing table data is received, it gets merged with the local routing table - * to keep the latest data. - */ - -public class RpcRegistryOld extends AbstractUntypedActor { - - private static final Logger LOG = LoggerFactory.getLogger(RpcRegistryOld.class); - private RoutingTableOld, String> routingTable; - private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - private final ClusterWrapper clusterWrapper; - private final ScheduledFuture syncScheduler; - - private RpcRegistryOld(ClusterWrapper clusterWrapper){ - this.routingTable = new RoutingTableOld<>(); - this.clusterWrapper = clusterWrapper; - this.syncScheduler = scheduler.scheduleAtFixedRate(new SendRoutingTable(), 10, 10, TimeUnit.SECONDS); - } - - public static Props props(final ClusterWrapper clusterWrapper){ - return Props.create(new Creator(){ - - @Override - public RpcRegistryOld create() throws Exception { - return new RpcRegistryOld(clusterWrapper); - } - }); - } - - @Override - protected void handleReceive(Object message) throws Exception { - LOG.debug("Received message {}", message); - if(message instanceof RoutingTableData) { - syncRoutingTable((RoutingTableData) message); - } else if(message instanceof GetRoutedRpc) { - getRoutedRpc((GetRoutedRpc) message); - } else if(message instanceof GetRpc) { - getRpc((GetRpc) message); - } else if(message instanceof AddRpc) { - addRpc((AddRpc) message); - } else if(message instanceof RemoveRpc) { - removeRpc((RemoveRpc) message); - } else if(message instanceof AddRoutedRpc) { - addRoutedRpc((AddRoutedRpc) message); - } else if(message instanceof RemoveRoutedRpc) { - removeRoutedRpc((RemoveRoutedRpc) message); - } - } - - private void getRoutedRpc(GetRoutedRpc rpcMsg){ - LOG.debug("Get latest routed Rpc location from routing table {}", rpcMsg); - String remoteActorPath = routingTable.getLastAddedRoutedRpc(rpcMsg.getRouteId()); - GetRoutedRpcReply routedRpcReply = new GetRoutedRpcReply(remoteActorPath); - - getSender().tell(routedRpcReply, self()); - } - - private void getRpc(GetRpc rpcMsg) { - LOG.debug("Get global Rpc location from routing table {}", rpcMsg); - String remoteActorPath = routingTable.getGlobalRoute(rpcMsg.getRouteId()); - GetRpcReply rpcReply = new GetRpcReply(remoteActorPath); - - getSender().tell(rpcReply, self()); - } - - private void addRpc(AddRpc rpcMsg) { - LOG.debug("Add Rpc to routing table {}", rpcMsg); - routingTable.addGlobalRoute(rpcMsg.getRouteId(), rpcMsg.getActorPath()); - - getSender().tell("Success", self()); - } - - private void removeRpc(RemoveRpc rpcMsg) { - LOG.debug("Removing Rpc to routing table {}", rpcMsg); - routingTable.removeGlobalRoute(rpcMsg.getRouteId()); - - getSender().tell("Success", self()); - } - - private void addRoutedRpc(AddRoutedRpc rpcMsg) { - routingTable.addRoutedRpcs(rpcMsg.getAnnouncements(), rpcMsg.getActorPath()); - getSender().tell("Success", self()); - } - - private void removeRoutedRpc(RemoveRoutedRpc rpcMsg) { - routingTable.removeRoutes(rpcMsg.getAnnouncements(), rpcMsg.getActorPath()); - getSender().tell("Success", self()); - } - - private void syncRoutingTable(RoutingTableData routingTableData) { - LOG.debug("Syncing routing table {}", routingTableData); - - Map, String> newRpcMap = routingTableData.getRpcMap(); - Set> routeIds = newRpcMap.keySet(); - for(RpcRouter.RouteIdentifier routeId : routeIds) { - routingTable.addGlobalRoute(routeId, newRpcMap.get(routeId)); - } - - Map, LinkedHashSet> newRoutedRpcMap = - routingTableData.getRoutedRpcMap(); - routeIds = newRoutedRpcMap.keySet(); - - for(RpcRouter.RouteIdentifier routeId : routeIds) { - Set routeAddresses = newRoutedRpcMap.get(routeId); - for(String routeAddress : routeAddresses) { - routingTable.addRoutedRpc(routeId, routeAddress); - } - } - } - - private ActorSelection getRandomRegistryActor() { - ClusterEvent.CurrentClusterState clusterState = clusterWrapper.getState(); - ActorSelection actor = null; - Set members = JavaConversions.asJavaSet(clusterState.members()); - int memberSize = members.size(); - // Don't select yourself - if(memberSize > 1) { - Address currentNodeAddress = clusterWrapper.getAddress(); - int index = new Random().nextInt(memberSize); - int i = 0; - // keeping previous member, in case when random index member is same as current actor - // and current actor member is last in set - Member previousMember = null; - for(Member member : members){ - if(i == index-1) { - previousMember = member; - } - if(i == index) { - if(!currentNodeAddress.equals(member.address())) { - actor = this.context().actorSelection(member.address() + ActorConstants.RPC_REGISTRY_PATH); - break; - } else if(index < memberSize-1){ // pick the next element in the set - index++; - } - } - i++; - } - if(actor == null && previousMember != null) { - actor = this.context().actorSelection(previousMember.address() + ActorConstants.RPC_REGISTRY_PATH); - } - } - return actor; - } - - private class SendRoutingTable implements Runnable { - - @Override - public void run() { - RoutingTableData routingTableData = - new RoutingTableData(routingTable.getGlobalRpcMap(), routingTable.getRoutedRpcMap()); - LOG.debug("Sending routing table for sync {}", routingTableData); - ActorSelection actor = getRandomRegistryActor(); - if(actor != null) { - actor.tell(routingTableData, self()); - } - } - } -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/ActorUtil.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/ActorUtil.java index 8f60eabf5f..b7b2216a08 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/ActorUtil.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/ActorUtil.java @@ -9,7 +9,6 @@ package org.opendaylight.controller.remote.rpc.utils; import akka.actor.ActorRef; -import akka.actor.ActorSelection; import akka.util.Timeout; import scala.concurrent.Await; import scala.concurrent.Future; @@ -36,27 +35,13 @@ public class ActorUtil { * @param awaitDuration * @return The response of the operation */ - public static Object executeLocalOperation(ActorRef actor, Object message, - FiniteDuration askDuration, FiniteDuration awaitDuration) throws Exception{ + public static Object executeOperation(ActorRef actor, Object message, + FiniteDuration askDuration, FiniteDuration awaitDuration) throws Exception{ Future future = ask(actor, message, new Timeout(askDuration)); return Await.result(future, awaitDuration); } - /** - * Execute an operation on a remote actor and wait for it's response - * @param actor - * @param message - * @param askDuration - * @param awaitDuration - * @return - */ - public static Object executeRemoteOperation(ActorSelection actor, Object message, - FiniteDuration askDuration, FiniteDuration awaitDuration) throws Exception{ - Future future = - ask(actor, message, new Timeout(askDuration)); - return Await.result(future, awaitDuration); - } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/LatestEntryRoutingLogic.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/LatestEntryRoutingLogic.java new file mode 100644 index 0000000000..f01baf009b --- /dev/null +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/LatestEntryRoutingLogic.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 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.remote.rpc.utils; + +import akka.actor.ActorRef; +import akka.japi.Pair; +import com.google.common.base.Preconditions; + +import java.util.Collection; +import java.util.Comparator; +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * This class will return First Entry + */ +public class LatestEntryRoutingLogic implements RoutingLogic{ + + private SortedSet> actorRefSet; + + public LatestEntryRoutingLogic(Collection> entries) { + Preconditions.checkNotNull(entries, "Entries should not be null"); + Preconditions.checkArgument(!entries.isEmpty(), "Entries collection should not be empty"); + + actorRefSet = new TreeSet<>(new LatestEntryComparator()); + actorRefSet.addAll(entries); + } + + @Override + public ActorRef select() { + return actorRefSet.last().first(); + } + + + private class LatestEntryComparator implements Comparator> { + + @Override + public int compare(Pair o1, Pair o2) { + if(o1 == null && o2 == null) { + return 0; + } + if(o1 == null && o2 != null) { + return -1; + } + if(o1 != null && o2 == null) { + return 1; + } + + return o1.second().compareTo(o2.second()); + + } + + } +} + + diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/RoutingLogic.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/RoutingLogic.java new file mode 100644 index 0000000000..4de71949fc --- /dev/null +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/RoutingLogic.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2014 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.remote.rpc.utils; + +import akka.actor.ActorRef; + +/** + * This Interface is added to abstract out the way rpc execution could be + * routed, if more than one node in cluster is capable of executing the rpc. + * + * We can pick node randomly, round robin manner or based on last updated time etc. + */ + +public interface RoutingLogic { + + ActorRef select(); +} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/resources/application.conf b/opendaylight/md-sal/sal-remoterpc-connector/src/main/resources/application.conf index daac89c4c8..711ae1c48b 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/resources/application.conf +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/resources/application.conf @@ -53,7 +53,6 @@ odl-cluster-rpc { cluster { seed-nodes = ["akka.tcp://opendaylight-cluster-rpc@127.0.0.1:2551"] - auto-down-unreachable-after = 10s } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/ActorSystemFactoryTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/ActorSystemFactoryTest.java new file mode 100644 index 0000000000..ed5fa6d16e --- /dev/null +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/ActorSystemFactoryTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 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.remote.rpc; + + +import akka.actor.ActorSystem; +import junit.framework.Assert; +import org.junit.After; +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; + +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ActorSystemFactoryTest { + ActorSystem system = null; + + @Test + public void testActorSystemCreation(){ + BundleContext context = mock(BundleContext.class); + when(context.getBundle()).thenReturn(mock(Bundle.class)); + ActorSystemFactory.createInstance(context); + system = ActorSystemFactory.getInstance(); + Assert.assertNotNull(system); + // Check illegal state exception + + try { + ActorSystemFactory.createInstance(context); + fail("Illegal State exception should be thrown, while creating actor system second time"); + } catch (IllegalStateException e) { + } + } + + @After + public void cleanup() throws InterruptedException { + if(system != null) { + system.shutdown(); + } + } + +} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderTest.java new file mode 100644 index 0000000000..17ad237ad7 --- /dev/null +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014 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.remote.rpc; + + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.testkit.JavaTestKit; +import com.typesafe.config.ConfigFactory; +import junit.framework.Assert; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import scala.concurrent.Await; +import scala.concurrent.duration.Duration; + + +import java.util.concurrent.TimeUnit; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class RemoteRpcProviderTest { + + static ActorSystem system; + + + @BeforeClass + public static void setup() throws InterruptedException { + system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster")); + } + + @AfterClass + public static void teardown() { + JavaTestKit.shutdownActorSystem(system); + system = null; + } + + @Test + public void testRemoteRpcProvider() throws Exception { + RemoteRpcProvider rpcProvider = new RemoteRpcProvider(system, mock(RpcProvisionRegistry.class)); + Broker.ProviderSession session = mock(Broker.ProviderSession.class); + SchemaService schemaService = mock(SchemaService.class); + when(schemaService.getGlobalContext()). thenReturn(mock(SchemaContext.class)); + when(session.getService(SchemaService.class)).thenReturn(schemaService); + rpcProvider.onSessionInitiated(session); + ActorRef actorRef = Await.result(system.actorSelection(ActorConstants.RPC_MANAGER_PATH).resolveOne(Duration.create(1, TimeUnit.SECONDS)), + Duration.create(2, TimeUnit.SECONDS)); + Assert.assertTrue(actorRef.path().toString().contains(ActorConstants.RPC_MANAGER_PATH)); + } + + + +} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RouteRpcListenerTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RouteRpcListenerTest.java new file mode 100644 index 0000000000..9b6215addd --- /dev/null +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RouteRpcListenerTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014 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.remote.rpc; + + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.testkit.JavaTestKit; +import com.typesafe.config.ConfigFactory; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils; +import org.opendaylight.controller.remote.rpc.registry.RpcRegistry; +import org.opendaylight.controller.sal.core.api.RpcRoutingContext; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; + +import java.net.URI; +import java.net.URISyntaxException; + +public class RouteRpcListenerTest { + + static ActorSystem system; + + + @BeforeClass + public static void setup() throws InterruptedException { + system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster")); + } + + @AfterClass + public static void teardown() { + JavaTestKit.shutdownActorSystem(system); + system = null; + } + + @Test + public void testRouteAdd() throws URISyntaxException, InterruptedException { + new JavaTestKit(system) { + { + // Test announcements + JavaTestKit probeReg = new JavaTestKit(system); + ActorRef rpcRegistry = probeReg.getRef(); + + RoutedRpcListener rpcListener = new RoutedRpcListener(rpcRegistry); + + QName qName = new QName(new URI("actor2"), "actor2"); + RpcRoutingContext context = RpcRoutingContext.create(qName, qName); + YangInstanceIdentifier identifier = YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(qName)); + rpcListener.onRouteChange(RoutingUtils.announcementChange(context, identifier)); + + probeReg.expectMsgClass(RpcRegistry.Messages.AddOrUpdateRoutes.class); + }}; + } + + @Test + public void testRouteRemove() throws URISyntaxException, InterruptedException { + new JavaTestKit(system) { + { + // Test announcements + JavaTestKit probeReg = new JavaTestKit(system); + ActorRef rpcRegistry = probeReg.getRef(); + + RoutedRpcListener rpcListener = new RoutedRpcListener(rpcRegistry); + + QName qName = new QName(new URI("actor2"), "actor2"); + RpcRoutingContext context = RpcRoutingContext.create(qName, qName); + YangInstanceIdentifier identifier = YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(qName)); + rpcListener.onRouteChange(RoutingUtils.removalChange(context, identifier)); + + probeReg.expectMsgClass(RpcRegistry.Messages.RemoveRoutes.class); + }}; + } +} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RpcBrokerTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RpcBrokerTest.java index 55aa1d6c87..d9a3b6a414 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RpcBrokerTest.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RpcBrokerTest.java @@ -11,23 +11,21 @@ package org.opendaylight.controller.remote.rpc; import akka.actor.ActorRef; import akka.actor.ActorSystem; +import akka.japi.Pair; import akka.testkit.JavaTestKit; import com.google.common.util.concurrent.Futures; +import com.typesafe.config.ConfigFactory; import junit.framework.Assert; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.mockito.Mockito; -import org.opendaylight.controller.remote.rpc.messages.AddRoutedRpc; -import org.opendaylight.controller.remote.rpc.messages.AddRpc; import org.opendaylight.controller.remote.rpc.messages.ErrorResponse; -import org.opendaylight.controller.remote.rpc.messages.InvokeRoutedRpc; import org.opendaylight.controller.remote.rpc.messages.InvokeRpc; import org.opendaylight.controller.remote.rpc.messages.RpcResponse; -import org.opendaylight.controller.remote.rpc.registry.ClusterWrapper; -import org.opendaylight.controller.remote.rpc.registry.RpcRegistryOld; +import org.opendaylight.controller.remote.rpc.registry.RpcRegistry; import org.opendaylight.controller.sal.common.util.Rpcs; -import org.opendaylight.controller.sal.connector.api.RpcRouter; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcError; @@ -35,7 +33,6 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.ModifyAction; import org.opendaylight.yangtools.yang.data.api.Node; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -43,8 +40,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.List; import java.util.concurrent.Future; import static org.mockito.Mockito.mock; @@ -52,31 +48,50 @@ import static org.mockito.Mockito.when; public class RpcBrokerTest { - static ActorSystem system; + static ActorSystem node1; + static ActorSystem node2; + private ActorRef rpcBroker1; + private JavaTestKit probeReg1; + private ActorRef rpcBroker2; + private JavaTestKit probeReg2; + private Broker.ProviderSession brokerSession; @BeforeClass - public static void setup() { - system = ActorSystem.create(); + public static void setup() throws InterruptedException { + node1 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberA")); + node2 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberB")); } @AfterClass public static void teardown() { - JavaTestKit.shutdownActorSystem(system); - system = null; + JavaTestKit.shutdownActorSystem(node1); + JavaTestKit.shutdownActorSystem(node2); + node1 = null; + node2 = null; } + @Before + public void createActor() { + brokerSession = Mockito.mock(Broker.ProviderSession.class); + SchemaContext schemaContext = mock(SchemaContext.class); + probeReg1 = new JavaTestKit(node1); + rpcBroker1 = node1.actorOf(RpcBroker.props(brokerSession, probeReg1.getRef(), schemaContext)); + probeReg2 = new JavaTestKit(node2); + rpcBroker2 = node2.actorOf(RpcBroker.props(brokerSession, probeReg2.getRef(), schemaContext)); + + } @Test - public void testInvokeRpcError() throws URISyntaxException { - new JavaTestKit(system) {{ - ActorRef rpcRegistry = system.actorOf(RpcRegistryOld.props(Mockito.mock(ClusterWrapper.class))); - Broker.ProviderSession brokerSession = Mockito.mock(Broker.ProviderSession.class); - SchemaContext schemaContext = mock(SchemaContext.class); - ActorRef rpcBroker = system.actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext)); + public void testInvokeRpcError() throws Exception { + new JavaTestKit(node1) {{ QName rpc = new QName(new URI("noactor1"), "noactor1"); CompositeNode input = new ImmutableCompositeNode(QName.create("ns", "2013-12-09", "no child"), new ArrayList>(), ModifyAction.REPLACE); - InvokeRpc invokeMsg = new InvokeRpc(rpc, input); - rpcBroker.tell(invokeMsg, getRef()); + + + InvokeRpc invokeMsg = new InvokeRpc(rpc, null, input); + rpcBroker1.tell(invokeMsg, getRef()); + probeReg1.expectMsgClass(RpcRegistry.Messages.FindRouters.class); + probeReg1.reply(new RpcRegistry.Messages.FindRoutersReply(new ArrayList>())); Boolean getMsg = new ExpectMsg("ErrorResponse") { protected Boolean match(Object in) { @@ -90,114 +105,36 @@ public class RpcBrokerTest { }.get(); // this extracts the received message Assert.assertTrue(getMsg); + }}; } + /** * This test method invokes and executes the remote rpc */ @Test public void testInvokeRpc() throws URISyntaxException { - new JavaTestKit(system) {{ - ActorRef rpcRegistry = system.actorOf(RpcRegistryOld.props(mock(ClusterWrapper.class))); - Broker.ProviderSession brokerSession = mock(Broker.ProviderSession.class); - SchemaContext schemaContext = mock(SchemaContext.class); - ActorRef rpcBroker = system.actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext)); - ActorRef rpcBrokerRemote = system.actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext), "actor1"); - // Add RPC in table - QName rpc = new QName(new URI("actor1"), "actor1"); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, rpc, null); - final String route = rpcBrokerRemote.path().toString(); - AddRpc rpcMsg = new AddRpc(routeId, route); - rpcRegistry.tell(rpcMsg, getRef()); - expectMsgEquals(duration("2 second"), "Success"); - + new JavaTestKit(node1) {{ + QName rpc = new QName(new URI("noactor1"), "noactor1"); // invoke rpc CompositeNode input = new ImmutableCompositeNode(QName.create("ns", "2013-12-09", "child1"), new ArrayList>(), ModifyAction.REPLACE); - CompositeNode invokeRpcResult = mock(CompositeNode.class); - Collection errors = new ArrayList<>(); - RpcResult result = Rpcs.getRpcResult(true, invokeRpcResult, errors); - Future> rpcResult = Futures.immediateFuture(result); - when(brokerSession.rpc(rpc, input)).thenReturn(rpcResult); - InvokeRpc invokeMsg = new InvokeRpc(rpc, input); - rpcBroker.tell(invokeMsg, getRef()); - - //verify response msg - Boolean getMsg = new ExpectMsg("RpcResponse") { - protected Boolean match(Object in) { - if (in instanceof RpcResponse) { - return true; - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - Assert.assertTrue(getMsg); - }}; - } - - @Test - public void testInvokeRoutedRpcError() throws URISyntaxException { - new JavaTestKit(system) {{ - ActorRef rpcRegistry = system.actorOf(RpcRegistryOld.props(Mockito.mock(ClusterWrapper.class))); - Broker.ProviderSession brokerSession = Mockito.mock(Broker.ProviderSession.class); - SchemaContext schemaContext = mock(SchemaContext.class); - ActorRef rpcBroker = system.actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext)); - QName rpc = new QName(new URI("actor1"), "actor1"); - CompositeNode input = new ImmutableCompositeNode(QName.create("ns", "2013-12-09", "child1"), new ArrayList>(), ModifyAction.REPLACE); - InvokeRoutedRpc invokeMsg = new InvokeRoutedRpc(rpc, YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(rpc)), input); - rpcBroker.tell(invokeMsg, getRef()); + InvokeRpc invokeMsg = new InvokeRpc(rpc, null, input); + rpcBroker1.tell(invokeMsg, getRef()); - Boolean getMsg = new ExpectMsg("ErrorResponse") { - protected Boolean match(Object in) { - if (in instanceof ErrorResponse) { - ErrorResponse reply = (ErrorResponse)in; - return "No remote actor found for rpc execution.".equals(reply.getException().getMessage()); - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - Assert.assertTrue(getMsg); - }}; - } + probeReg1.expectMsgClass(RpcRegistry.Messages.FindRouters.class); + List> routerList = new ArrayList>(); - /** - * This test method invokes and executes the remote routed rpc - */ + routerList.add(new Pair(rpcBroker2, 200L)); - @Test - public void testInvokeRoutedRpc() throws URISyntaxException { - new JavaTestKit(system) {{ - ActorRef rpcRegistry = system.actorOf(RpcRegistryOld.props(mock(ClusterWrapper.class))); - Broker.ProviderSession brokerSession = mock(Broker.ProviderSession.class); - SchemaContext schemaContext = mock(SchemaContext.class); - ActorRef rpcBroker = system.actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext)); - ActorRef rpcBrokerRemote = system.actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext), "actor2"); - // Add Routed RPC in table - QName rpc = new QName(new URI("actor2"), "actor2"); - YangInstanceIdentifier identifier = YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(rpc)); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, rpc, identifier); - final String route = rpcBrokerRemote.path().toString(); - Set> routeIds = new HashSet<>(); - routeIds.add(routeId); - - AddRoutedRpc rpcMsg = new AddRoutedRpc(routeIds, route); - rpcRegistry.tell(rpcMsg, getRef()); - expectMsgEquals(duration("2 second"), "Success"); + probeReg1.reply(new RpcRegistry.Messages.FindRoutersReply(routerList)); - // invoke rpc - CompositeNode input = new ImmutableCompositeNode(QName.create("ns", "2013-12-09", "child1"), new ArrayList>(), ModifyAction.REPLACE); CompositeNode invokeRpcResult = mock(CompositeNode.class); Collection errors = new ArrayList<>(); RpcResult result = Rpcs.getRpcResult(true, invokeRpcResult, errors); Future> rpcResult = Futures.immediateFuture(result); when(brokerSession.rpc(rpc, input)).thenReturn(rpcResult); - InvokeRoutedRpc invokeMsg = new InvokeRoutedRpc(rpc, identifier, input); - rpcBroker.tell(invokeMsg, getRef()); //verify response msg Boolean getMsg = new ExpectMsg("RpcResponse") { @@ -213,5 +150,4 @@ public class RpcBrokerTest { Assert.assertTrue(getMsg); }}; } - } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RpcListenerTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RpcListenerTest.java new file mode 100644 index 0000000000..7b5a968866 --- /dev/null +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RpcListenerTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014 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.remote.rpc; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.testkit.JavaTestKit; +import com.typesafe.config.ConfigFactory; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.controller.remote.rpc.registry.RpcRegistry; +import org.opendaylight.yangtools.yang.common.QName; + +import java.net.URI; +import java.net.URISyntaxException; + +public class RpcListenerTest { + + static ActorSystem system; + + + @BeforeClass + public static void setup() throws InterruptedException { + system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster")); + } + + @AfterClass + public static void teardown() { + JavaTestKit.shutdownActorSystem(system); + system = null; + } + + @Test + public void testRpcAdd() throws URISyntaxException { + new JavaTestKit(system) { + { + JavaTestKit probeReg = new JavaTestKit(system); + ActorRef rpcRegistry = probeReg.getRef(); + + RpcListener rpcListener = new RpcListener(rpcRegistry); + + QName qName = new QName(new URI("actor2"), "actor2"); + + rpcListener.onRpcImplementationAdded(qName); + probeReg.expectMsgClass(RpcRegistry.Messages.AddOrUpdateRoutes.class); + }}; + + } + + @Test + public void testRpcRemove() throws URISyntaxException { + new JavaTestKit(system) { + { + JavaTestKit probeReg = new JavaTestKit(system); + ActorRef rpcRegistry = probeReg.getRef(); + + RpcListener rpcListener = new RpcListener(rpcRegistry); + + QName qName = new QName(new URI("actor2"), "actor2"); + + rpcListener.onRpcImplementationRemoved(qName); + probeReg.expectMsgClass(RpcRegistry.Messages.RemoveRoutes.class); + }}; + + } +} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RoutingTableOldTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RoutingTableOldTest.java deleted file mode 100644 index 524a91288d..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RoutingTableOldTest.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.registry; - -import junit.framework.Assert; -import org.junit.Test; -import org.opendaylight.controller.remote.rpc.RouteIdentifierImpl; -import org.opendaylight.controller.sal.connector.api.RpcRouter; -import org.opendaylight.yangtools.yang.common.QName; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.HashSet; -import java.util.Set; - -public class RoutingTableOldTest { - - private RoutingTableOld, String> routingTable = - new RoutingTableOld<>(); - - @Test - public void addGlobalRouteNullRouteIdTest() { - try { - routingTable.addGlobalRoute(null, null); - - Assert.fail("Null pointer exception was not thrown."); - } catch (Exception e) { - Assert.assertEquals(NullPointerException.class.getName(), e.getClass().getName()); - Assert.assertEquals("addGlobalRoute: routeId cannot be null!", e.getMessage()); - } - } - - @Test - public void addGlobalRouteNullRouteTest() { - try { - QName type = new QName(new URI("actor1"), "actor1"); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null); - routingTable.addGlobalRoute(routeId, null); - - Assert.fail("Null pointer exception was not thrown."); - } catch (Exception e) { - Assert.assertEquals(NullPointerException.class.getName(), e.getClass().getName()); - Assert.assertEquals("addGlobalRoute: route cannot be null!", e.getMessage()); - } - } - - @Test - public void getGlobalRouteNullTest() { - try { - routingTable.getGlobalRoute(null); - - Assert.fail("Null pointer exception was not thrown."); - } catch (Exception e) { - Assert.assertEquals(NullPointerException.class.getName(), e.getClass().getName()); - Assert.assertEquals("getGlobalRoute: routeId cannot be null!", e.getMessage()); - } - } - - @Test - public void getGlobalRouteTest() throws URISyntaxException { - QName type = new QName(new URI("actor1"), "actor1"); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null); - String route = "actor1"; - - routingTable.addGlobalRoute(routeId, route); - - String returnedRoute = routingTable.getGlobalRoute(routeId); - - Assert.assertEquals(route, returnedRoute); - - } - - @Test - public void removeGlobalRouteTest() throws URISyntaxException { - QName type = new QName(new URI("actorRemove"), "actorRemove"); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null); - String route = "actorRemove"; - - routingTable.addGlobalRoute(routeId, route); - - String returnedRoute = routingTable.getGlobalRoute(routeId); - - Assert.assertEquals(route, returnedRoute); - - routingTable.removeGlobalRoute(routeId); - - String deletedRoute = routingTable.getGlobalRoute(routeId); - - Assert.assertNull(deletedRoute); - } - - @Test - public void addRoutedRpcNullRouteIdTest() { - try { - routingTable.addRoutedRpc(null, null); - - Assert.fail("Null pointer exception was not thrown."); - } catch (Exception e) { - Assert.assertEquals(NullPointerException.class.getName(), e.getClass().getName()); - Assert.assertEquals("addRoute: routeId cannot be null", e.getMessage()); - } - } - - @Test - public void addRoutedRpcNullRouteTest() { - try { - QName type = new QName(new URI("actor1"), "actor1"); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null); - - routingTable.addRoutedRpc(routeId, null); - - Assert.fail("Null pointer exception was not thrown."); - } catch (Exception e) { - Assert.assertEquals(NullPointerException.class.getName(), e.getClass().getName()); - Assert.assertEquals("addRoute: route cannot be null", e.getMessage()); - } - } - - @Test - public void getRoutedRpcNullTest() { - try { - routingTable.getRoutedRpc(null); - - Assert.fail("Null pointer exception was not thrown."); - } catch (Exception e) { - Assert.assertEquals(NullPointerException.class.getName(), e.getClass().getName()); - Assert.assertEquals("getRoutes: routeId cannot be null!", e.getMessage()); - } - } - - @Test - public void getRoutedRpcTest() throws URISyntaxException { - QName type = new QName(new URI("actor1"), "actor1"); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null); - String route = "actor1"; - - routingTable.addRoutedRpc(routeId, route); - - Set routes = routingTable.getRoutedRpc(routeId); - - Assert.assertEquals(1, routes.size()); - Assert.assertTrue(routes.contains(route)); - - } - - @Test - public void getLastRoutedRpcTest() throws URISyntaxException { - QName type = new QName(new URI("first1"), "first1"); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null); - String route = "first1"; - - routingTable.addRoutedRpc(routeId, route); - - String route2 = "second1"; - routingTable.addRoutedRpc(routeId, route2); - - String latest = routingTable.getLastAddedRoutedRpc(routeId); - Assert.assertEquals(route2, latest); - - } - - @Test - public void removeRoutedRpcTest() throws URISyntaxException { - QName type = new QName(new URI("remove"), "remove"); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null); - String route = "remove"; - routingTable.addRoutedRpc(routeId, route); - - String latest = routingTable.getLastAddedRoutedRpc(routeId); - Assert.assertEquals(route, latest); - - routingTable.removeRoute(routeId, route); - String removed = routingTable.getLastAddedRoutedRpc(routeId); - Assert.assertNull(removed); - } - - @Test - public void removeRoutedRpcsTest() throws URISyntaxException { - QName type = new QName(new URI("remove1"), "remove1"); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null); - - QName type2 = new QName(new URI("remove2"), "remove2"); - RouteIdentifierImpl routeId2 = new RouteIdentifierImpl(null, type2, null); - - Set> routeIds = new HashSet<>(); - routeIds.add(routeId); - routeIds.add(routeId2); - String route = "remove1"; - - routingTable.addRoutedRpcs(routeIds, route); - String latest1 = routingTable.getLastAddedRoutedRpc(routeId); - Assert.assertEquals(route, latest1); - - String latest2 = routingTable.getLastAddedRoutedRpc(routeId2); - Assert.assertEquals(route, latest2); - - routingTable.removeRoutes(routeIds, route); - String removed1 = routingTable.getLastAddedRoutedRpc(routeId); - Assert.assertNull(removed1); - - String removed2 = routingTable.getLastAddedRoutedRpc(routeId2); - Assert.assertNull(removed2); - } - -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryOldTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryOldTest.java deleted file mode 100644 index 0f711b4e85..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryOldTest.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2014 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.remote.rpc.registry; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.testkit.JavaTestKit; -import junit.framework.Assert; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mockito; -import org.opendaylight.controller.remote.rpc.RouteIdentifierImpl; -import org.opendaylight.controller.remote.rpc.messages.AddRoutedRpc; -import org.opendaylight.controller.remote.rpc.messages.AddRpc; -import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpc; -import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpcReply; -import org.opendaylight.controller.remote.rpc.messages.GetRpc; -import org.opendaylight.controller.remote.rpc.messages.GetRpcReply; -import org.opendaylight.controller.remote.rpc.messages.RemoveRoutedRpc; -import org.opendaylight.controller.remote.rpc.messages.RemoveRpc; -import org.opendaylight.controller.sal.connector.api.RpcRouter; -import org.opendaylight.yangtools.yang.common.QName; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.HashSet; -import java.util.Set; - -public class RpcRegistryOldTest { - - static ActorSystem system; - - - @BeforeClass - public static void setup() { - system = ActorSystem.create(); - } - - @AfterClass - public static void teardown() { - JavaTestKit.shutdownActorSystem(system); - system = null; - } - - /** - This test add, read and remove an entry in global rpc - */ - @Test - public void testGlobalRpc() throws URISyntaxException { - new JavaTestKit(system) {{ - ActorRef rpcRegistry = system.actorOf(RpcRegistryOld.props(Mockito.mock(ClusterWrapper.class))); - QName type = new QName(new URI("actor1"), "actor1"); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null); - final String route = "actor1"; - - AddRpc rpcMsg = new AddRpc(routeId, route); - rpcRegistry.tell(rpcMsg, getRef()); - expectMsgEquals(duration("2 second"), "Success"); - - GetRpc getRpc = new GetRpc(routeId); - rpcRegistry.tell(getRpc, getRef()); - - Boolean getMsg = new ExpectMsg("GetRpcReply") { - protected Boolean match(Object in) { - if (in instanceof GetRpcReply) { - GetRpcReply reply = (GetRpcReply)in; - return route.equals(reply.getRoutePath()); - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - Assert.assertTrue(getMsg); - - RemoveRpc removeMsg = new RemoveRpc(routeId); - rpcRegistry.tell(removeMsg, getRef()); - expectMsgEquals(duration("2 second"), "Success"); - - rpcRegistry.tell(getRpc, getRef()); - - Boolean getNullMsg = new ExpectMsg("GetRpcReply") { - protected Boolean match(Object in) { - if (in instanceof GetRpcReply) { - GetRpcReply reply = (GetRpcReply)in; - return reply.getRoutePath() == null; - } else { - throw noMatch(); - } - } - }.get(); - Assert.assertTrue(getNullMsg); - }}; - - } - - /** - This test add, read and remove an entry in routed rpc - */ - @Test - public void testRoutedRpc() throws URISyntaxException { - new JavaTestKit(system) {{ - ActorRef rpcRegistry = system.actorOf(RpcRegistryOld.props(Mockito.mock(ClusterWrapper.class))); - QName type = new QName(new URI("actor1"), "actor1"); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null); - final String route = "actor1"; - - Set> routeIds = new HashSet<>(); - routeIds.add(routeId); - - AddRoutedRpc rpcMsg = new AddRoutedRpc(routeIds, route); - rpcRegistry.tell(rpcMsg, getRef()); - expectMsgEquals(duration("2 second"), "Success"); - - GetRoutedRpc getRpc = new GetRoutedRpc(routeId); - rpcRegistry.tell(getRpc, getRef()); - - Boolean getMsg = new ExpectMsg("GetRoutedRpcReply") { - protected Boolean match(Object in) { - if (in instanceof GetRoutedRpcReply) { - GetRoutedRpcReply reply = (GetRoutedRpcReply)in; - return route.equals(reply.getRoutePath()); - } else { - throw noMatch(); - } - } - }.get(); // this extracts the received message - - Assert.assertTrue(getMsg); - - RemoveRoutedRpc removeMsg = new RemoveRoutedRpc(routeIds, route); - rpcRegistry.tell(removeMsg, getRef()); - expectMsgEquals(duration("2 second"), "Success"); - - rpcRegistry.tell(getRpc, getRef()); - - Boolean getNullMsg = new ExpectMsg("GetRoutedRpcReply") { - protected Boolean match(Object in) { - if (in instanceof GetRoutedRpcReply) { - GetRoutedRpcReply reply = (GetRoutedRpcReply)in; - return reply.getRoutePath() == null; - } else { - throw noMatch(); - } - } - }.get(); - Assert.assertTrue(getNullMsg); - }}; - - } - -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStoreTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStoreTest.java index 7e87da0f99..fd6664af9e 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStoreTest.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStoreTest.java @@ -34,7 +34,7 @@ public class BucketStoreTest { @BeforeClass public static void setup() { - system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("unit-test")); + system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster")); system.actorOf(Props.create(TerminationMonitor.class), "termination-monitor"); store = createStore(); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/GossiperTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/GossiperTest.java index f076c136fe..bb60ed6eec 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/GossiperTest.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/GossiperTest.java @@ -45,8 +45,7 @@ public class GossiperTest { @BeforeClass public static void setup() throws InterruptedException { - Thread.sleep(1000);//give some time for previous test to stop the system. Netty port conflict arises otherwise. - system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("unit-test")); + system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster")); system.actorOf(Props.create(TerminationMonitor.class), "termination-monitor"); gossiper = createGossiper(); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/utils/LatestEntryRoutingLogicTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/utils/LatestEntryRoutingLogicTest.java new file mode 100644 index 0000000000..b21f0f0069 --- /dev/null +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/utils/LatestEntryRoutingLogicTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014 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.remote.rpc.utils; + + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.japi.Pair; +import akka.testkit.JavaTestKit; +import akka.testkit.TestProbe; +import com.typesafe.config.ConfigFactory; +import junit.framework.Assert; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + + +public class LatestEntryRoutingLogicTest { + + static ActorSystem system; + + @BeforeClass + public static void setup() throws InterruptedException { + system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster")); + } + + @AfterClass + public static void teardown() { + JavaTestKit.shutdownActorSystem(system); + system = null; + } + + @Test + public void testRoutingLogic() { + List> pairList = new ArrayList<>(); + TestProbe probe1 = new TestProbe(system); + TestProbe probe2 = new TestProbe(system); + TestProbe probe3 = new TestProbe(system); + ActorRef actor1 = probe1.ref(); + ActorRef actor2 = probe2.ref(); + ActorRef actor3 = probe3.ref(); + pairList.add(new Pair(actor1, 1000L)); + pairList.add(new Pair(actor2, 3000L)); + pairList.add(new Pair(actor3, 2000L)); + RoutingLogic logic = new LatestEntryRoutingLogic(pairList); + Assert.assertTrue(logic.select().equals(actor2)); + } +} 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..61fab7e0fe 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" - port = 2551 + hostname = "127.0.0.1" + port = 2550 } } cluster { - seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"] + seed-nodes = ["akka.tcp://opendaylight-rpc@127.0.0.1:2550"] 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/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfError.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfError.java index ed20bd01a5..544a144987 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfError.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfError.java @@ -62,7 +62,7 @@ public class RestconfError { RESOURCE_DENIED("resource-denied", 409 /* Conflict */), ROLLBACK_FAILED("rollback-failed", 500 /* INTERNAL_SERVER_ERROR */), DATA_EXISTS("data-exists", 409 /* Conflict */), - DATA_MISSING("data-missing", 409 /* Conflict */), + DATA_MISSING("data-missing", 404 /* Resource Not Found */), OPERATION_NOT_SUPPORTED("operation-not-supported", 501 /* Not Implemented */), OPERATION_FAILED("operation-failed", 500 /* INTERNAL_SERVER_ERROR */), PARTIAL_OPERATION("partial-operation", 500 /* INTERNAL_SERVER_ERROR */), diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java index 25ba411f31..4e9c96ac3e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java @@ -374,7 +374,7 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { public void testToJsonResponseWithDataMissingErrorTag() throws Exception { testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING), - Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "mock error", null, null); + Status.NOT_FOUND, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "mock error", null, null); } @Test @@ -594,7 +594,7 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { public void testToXMLResponseWithDataMissingErrorTag() throws Exception { testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING), - Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "mock error", null, null); + Status.NOT_FOUND, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "mock error", null, null); } @Test diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfErrorTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfErrorTest.java index 18311104a4..010572de96 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfErrorTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfErrorTest.java @@ -90,7 +90,7 @@ public class RestconfErrorTest { lookUpMap.put("resource-denied", 409); lookUpMap.put("rollback-failed", 500); lookUpMap.put("data-exists", 409); - lookUpMap.put("data-missing", 409); + lookUpMap.put("data-missing", 404); lookUpMap.put("operation-not-supported", 501); lookUpMap.put("operation-failed", 500); lookUpMap.put("partial-operation", 500); diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java index 388c78eaaf..5832e29a13 100644 --- a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java +++ b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java @@ -76,9 +76,17 @@ public final class ToasterProviderModule extends dataChangeListenerRegistration.close(); rpcRegistration.close(); runtimeReg.close(); - opendaylightToaster.close(); + closeQuietly(opendaylightToaster); log.info("Toaster provider (instance {}) torn down.", this); } + + private void closeQuietly(final AutoCloseable resource) { + try { + resource.close(); + } catch (final Exception e) { + log.debug("Ignoring exception while closing {}", resource, e); + } + } } AutoCloseable ret = new AutoCloseableToaster(); diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java index b1db280c24..cd9738c894 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java @@ -32,6 +32,9 @@ final class FlowComparator { } public static boolean flowEquals(Flow statsFlow, Flow storedFlow) { + if (statsFlow == null || storedFlow == null) { + return false; + } if (statsFlow.getClass() != storedFlow.getClass()) { return false; } @@ -42,19 +45,18 @@ final class FlowComparator { } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) { return false; } - if (statsFlow.getMatch()== null) { - if (storedFlow.getMatch() != null) { + if (storedFlow.getPriority() == null) { + if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) { return false; } - } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) { - else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) { + } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) { return false; } - if (storedFlow.getPriority() == null) { - if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) { + if (statsFlow.getMatch()== null) { + if (storedFlow.getMatch() != null) { return false; } - } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) { + } else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) { return false; } if (statsFlow.getTableId() == null) { 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..e92d0bd625 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 @@ -7,14 +7,20 @@ */ package org.opendaylight.controller.md.statistics.manager; +import java.math.BigInteger; import java.util.Collection; +import java.util.Collections; import java.util.Map.Entry; import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCookieMapping; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMapBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMapKey; 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.TableKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; @@ -29,18 +35,24 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.O import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; 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; +import com.google.common.base.Optional; + final class FlowStatsTracker extends AbstractListeningStatsTracker { - private static final Logger logger = LoggerFactory.getLogger(FlowStatsTracker.class); + private static final Logger LOG = LoggerFactory.getLogger(FlowStatsTracker.class); + private static final String ALIEN_SYSTEM_FLOW_ID = "#UF$TABLE*"; private final OpendaylightFlowStatisticsService flowStatsService; private FlowTableStatsTracker flowTableStats; private int unaccountedFlowsCounter = 1; + FlowStatsTracker(final OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context) { super(context); this.flowStatsService = flowStatsService; @@ -52,11 +64,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); } @@ -66,15 +77,15 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker tableRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); - - //TODO: Not a good way to do it, need to figure out better way. - //TODO: major issue in any alternate approach is that flow key is incrementally assigned - //to the flows stored in data store. - // Augment same statistics to all the matching masked flow - Table table= (Table)trans.readConfigurationData(tableRef); - if(table != null){ - for(Flow existingFlow : table.getFlow()){ - logger.debug("Existing flow in data store : {}",existingFlow.toString()); - if(FlowComparator.flowEquals(flowRule,existingFlow)){ - InstanceIdentifier flowRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,existingFlow.getKey()).toInstance(); - flow.setKey(existingFlow.getKey()); - flow.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - logger.debug("Found matching flow in the datastore, augmenting statistics"); - // Update entry with timestamp of latest response - FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build()); - trans.putOperationalData(flowRef, flow.build()); - return flowStatsEntry; - } + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)).toInstance(); + + final FlowCookie flowCookie = flowRule.getCookie() != null + ? flowRule.getCookie() : new FlowCookie(BigInteger.ZERO); + final InstanceIdentifier flowCookieRef = tableRef + .augmentation(FlowCookieMapping.class) + .child(FlowCookieMap.class, new FlowCookieMapKey(flowCookie)); + + FlowCookieMap cookieMap = (FlowCookieMap) trans.readOperationalData(flowCookieRef); + + /* find flowKey in FlowCookieMap from DataStore/OPERATIONAL */ + Optional flowKey = this.getExistFlowKey(flowRule, tableRef, trans, cookieMap); + if ( ! flowKey.isPresent()) { + /* DataStore/CONFIG For every first statistic needs to be created */ + flowKey = this.getFlowKeyFromExistFlow(flowRule, tableRef, trans); + if ( ! flowKey.isPresent()) { + /* Alien flow */ + flowKey = this.makeAlienFlowKey(flowRule); } + cookieMap = applyNewFlowKey(cookieMap, flowKey, flowCookie); + trans.putOperationalData(flowCookieRef, cookieMap); } - table = (Table)trans.readOperationalData(tableRef); - if(table != null){ - for(Flow existingFlow : table.getFlow()){ - FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class); - if(augmentedflowStatisticsData != null){ - FlowBuilder existingOperationalFlow = new FlowBuilder(); - existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics()); - logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString()); - if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){ - InstanceIdentifier flowRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,existingFlow.getKey()).toInstance(); - flow.setKey(existingFlow.getKey()); - flow.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics"); - // Update entry with timestamp of latest response - FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build()); - trans.putOperationalData(flowRef, flow.build()); - return flowStatsEntry; - } - } - } - } - - String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter); - this.unaccountedFlowsCounter++; - FlowKey newFlowKey = new FlowKey(new FlowId(flowKey)); - InstanceIdentifier flowRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,newFlowKey).toInstance(); - flow.setKey(newFlowKey); - flow.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow", - flow.build()); + InstanceIdentifier flowRef = getNodeIdentifierBuilder() + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class, flowKey.get()).toInstance(); + flowBuilder.setKey(flowKey.get()); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); // Update entry with timestamp of latest response - flow.setKey(newFlowKey); - FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build()); - trans.putOperationalData(flowRef, flow.build()); + flowBuilder.setKey(flowKey.get()); + FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId, flowBuilder.build()); + trans.putOperationalData(flowRef, flowBuilder.build()); return flowStatsEntry; } @@ -180,9 +160,9 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker tables = flowTableStats.getTables(); - logger.debug("Node {} supports {} table(s)", this.getNodeRef(), tables.size()); + LOG.debug("Node {} supports {} table(s)", this.getNodeRef(), tables.size()); for (final TableKey key : tables) { - logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), this.getNodeRef()); + LOG.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), this.getNodeRef()); this.requestAggregateFlows(key); } @@ -224,10 +204,10 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker, DataObject> e : change.getCreatedConfigurationData().entrySet()) { if (Flow.class.equals(e.getKey().getTargetType())) { final Flow flow = (Flow) e.getValue(); - logger.debug("Key {} triggered request for flow {}", e.getKey(), flow); + LOG.debug("Key {} triggered request for flow {}", e.getKey(), flow); requestFlow(flow); } else { - logger.debug("Ignoring key {}", e.getKey()); + LOG.debug("Ignoring key {}", e.getKey()); } } @@ -236,7 +216,7 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker flow = (InstanceIdentifier)key; - logger.debug("Key {} triggered remove of Flow from operational space.", key); + LOG.debug("Key {} triggered remove of Flow from operational space.", key); trans.removeOperationalData(flow); } } @@ -246,10 +226,79 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker getExistFlowKey(final Flow flowRule, final InstanceIdentifier
tableRef, + final DataModificationTransaction trans, final FlowCookieMap cookieMap) { + + if (cookieMap != null) { + for (FlowId flowId : cookieMap.getFlowIds()) { + InstanceIdentifier flowIdent = tableRef.child(Flow.class, new FlowKey(flowId)); + if (flowId.getValue().startsWith(ALIEN_SYSTEM_FLOW_ID)) { + LOG.debug("Search for flow in the operational datastore by flowID: {} ", flowIdent); + Flow readedFlow = (Flow) trans.readOperationalData(flowIdent); + if (FlowComparator.flowEquals(flowRule, readedFlow)) { + return Optional. of(new FlowKey(flowId)); + } + } else { + LOG.debug("Search for flow in the configuration datastore by flowID: {} ", flowIdent); + Flow readedFlow = (Flow) trans.readConfigurationData(flowIdent); + if (FlowComparator.flowEquals(flowRule, readedFlow)) { + return Optional. of(new FlowKey(flowId)); + } + } + } + LOG.debug("Flow was not found in the datastore. Flow {} ", flowRule); + } + return Optional.absent(); + } + + /* Returns FlowKey from existing Flow in DataStore/CONFIGURATIONAL which is identified by cookie + * and by switch flow identification (priority and match) */ + private Optional getFlowKeyFromExistFlow(final Flow flowRule, final InstanceIdentifier
tableRef, + final DataModificationTransaction trans) { + + /* Try to find it in DataSotre/CONFIG */ + Table table= (Table)trans.readConfigurationData(tableRef); + if(table != null) { + for(Flow existingFlow : table.getFlow()) { + LOG.debug("Existing flow in data store : {}",existingFlow.toString()); + if(FlowComparator.flowEquals(flowRule,existingFlow)){ + return Optional. of(new FlowKey(existingFlow.getId())); + } + } + } + return Optional.absent(); + } + + /* Returns FlowKey which doesn't exist in any DataStore for now */ + private Optional makeAlienFlowKey(final Flow flowRule) { + + StringBuilder sBuilder = new StringBuilder(ALIEN_SYSTEM_FLOW_ID) + .append(flowRule.getTableId()).append("-").append(this.unaccountedFlowsCounter); + this.unaccountedFlowsCounter++; + final FlowId flowId = new FlowId(sBuilder.toString()); + return Optional. of(new FlowKey(flowId)); + } + + /* Build new whole FlowCookieMap or add new flowKey */ + private FlowCookieMap applyNewFlowKey(FlowCookieMap flowCookieMap, final Optional flowKey, + final FlowCookie flowCookie) { + if (flowCookieMap != null) { + flowCookieMap.getFlowIds().add(flowKey.get().getId()); + } else { + final FlowCookieMapBuilder flowCookieMapBuilder = new FlowCookieMapBuilder(); + flowCookieMapBuilder.setCookie(flowCookie); + flowCookieMapBuilder.setFlowIds(Collections.singletonList(flowKey.get().getId())); + flowCookieMap = flowCookieMapBuilder.build(); + } + return flowCookieMap; + } } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java index 701911d9a2..e4490eaa3c 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java @@ -31,12 +31,12 @@ final class NodeConnectorStatsTracker extends AbstractStatsTracker nodeConnectorRef = getNodeIdentifierBuilder() - .child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId())).build(); + final NodeConnectorKey key = new NodeConnectorKey(item.getNodeConnectorId()); + final InstanceIdentifier nodeConnectorRef = getNodeIdentifier().child(NodeConnector.class, key); // FIXME: can we bypass this read? NodeConnector nodeConnector = (NodeConnector)trans.readOperationalData(nodeConnectorRef); if(nodeConnector != null){ final FlowCapableNodeConnectorStatisticsData stats = statisticsDataBuilder.build(); logger.debug("Augmenting port statistics {} to port {}",stats,nodeConnectorRef.toString()); - NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder(); - nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats); + NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder() + .setKey(key).setId(item.getNodeConnectorId()) + .addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats); trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build()); } 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..556047091c 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 @@ -9,11 +9,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,24 +39,23 @@ 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"; final TopologyKey key = new TopologyKey(new TopologyId(name)); final InstanceIdentifier path = InstanceIdentifier - .builder(NetworkTopology.class) - .child(Topology.class, key) - .build(); + .create(NetworkTopology.class) + .child(Topology.class, key); - 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(), true); 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/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java index 2f7bd20d61..6826b4a09c 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java @@ -49,6 +49,7 @@ import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFact import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler; import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProviderImpl; import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; @@ -136,7 +137,7 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest { } public AuthProvider getAuthProvider() throws Exception { - AuthProvider mock = mock(AuthProvider.class); + AuthProvider mock = mock(AuthProviderImpl.class); doReturn(true).when(mock).authenticated(anyString(), anyString()); doReturn(PEMGenerator.generate().toCharArray()).when(mock).getPEMAsCharArray(); return mock; diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java index 5d39dd1eb8..92f3861c05 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java @@ -1,81 +1,16 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.controller.netconf.ssh.authentication; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.annotations.VisibleForTesting; -import org.opendaylight.controller.sal.authorization.AuthResultEnum; -import org.opendaylight.controller.usermanager.IUserManager; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.util.tracker.ServiceTracker; -import org.osgi.util.tracker.ServiceTrackerCustomizer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AuthProvider { - private static final Logger logger = LoggerFactory.getLogger(AuthProvider.class); - - private final String pem; - private IUserManager nullableUserManager; - public AuthProvider(String pemCertificate, final BundleContext bundleContext) { - checkNotNull(pemCertificate, "Parameter 'pemCertificate' is null"); - pem = pemCertificate; - - ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer() { - @Override - public IUserManager addingService(final ServiceReference reference) { - logger.trace("Service {} added", reference); - nullableUserManager = bundleContext.getService(reference); - return nullableUserManager; - } - - @Override - public void modifiedService(final ServiceReference reference, final IUserManager service) { - logger.trace("Replacing modified service {} in netconf SSH.", reference); - nullableUserManager = service; - } - - @Override - public void removedService(final ServiceReference reference, final IUserManager service) { - logger.trace("Removing service {} from netconf SSH. " + - "SSH won't authenticate users until IUserManager service will be started.", reference); - synchronized (AuthProvider.this) { - nullableUserManager = null; - } - } - }; - ServiceTracker listenerTracker = new ServiceTracker<>(bundleContext, IUserManager.class, customizer); - listenerTracker.open(); - } +package org.opendaylight.controller.netconf.ssh.authentication; - /** - * Authenticate user. This implementation tracks IUserManager and delegates the decision to it. If the service is not - * available, IllegalStateException is thrown. - */ - public synchronized boolean authenticated(String username, String password) { - if (nullableUserManager == null) { - logger.warn("Cannot authenticate user '{}', user manager service is missing", username); - throw new IllegalStateException("User manager service is not available"); - } - AuthResultEnum authResult = nullableUserManager.authenticate(username, password); - logger.debug("Authentication result for user '{}' : {}", username, authResult); - return authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC); - } +public interface AuthProvider { - public char[] getPEMAsCharArray() { - return pem.toCharArray(); - } + boolean authenticated(String username, String password); - @VisibleForTesting - void setNullableUserManager(IUserManager nullableUserManager) { - this.nullableUserManager = nullableUserManager; - } + char[] getPEMAsCharArray(); } diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProviderImpl.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProviderImpl.java new file mode 100644 index 0000000000..7543d17c06 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProviderImpl.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.netconf.ssh.authentication; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.VisibleForTesting; +import org.opendaylight.controller.sal.authorization.AuthResultEnum; +import org.opendaylight.controller.usermanager.IUserManager; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AuthProviderImpl implements AuthProvider { + private static final Logger logger = LoggerFactory.getLogger(AuthProviderImpl.class); + + private final String pem; + private IUserManager nullableUserManager; + + public AuthProviderImpl(String pemCertificate, final BundleContext bundleContext) { + checkNotNull(pemCertificate, "Parameter 'pemCertificate' is null"); + pem = pemCertificate; + + ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer() { + @Override + public IUserManager addingService(final ServiceReference reference) { + logger.trace("Service {} added", reference); + nullableUserManager = bundleContext.getService(reference); + return nullableUserManager; + } + + @Override + public void modifiedService(final ServiceReference reference, final IUserManager service) { + logger.trace("Replacing modified service {} in netconf SSH.", reference); + nullableUserManager = service; + } + + @Override + public void removedService(final ServiceReference reference, final IUserManager service) { + logger.trace("Removing service {} from netconf SSH. " + + "SSH won't authenticate users until IUserManager service will be started.", reference); + synchronized (AuthProviderImpl.this) { + nullableUserManager = null; + } + } + }; + ServiceTracker listenerTracker = new ServiceTracker<>(bundleContext, IUserManager.class, customizer); + listenerTracker.open(); + } + + /** + * Authenticate user. This implementation tracks IUserManager and delegates the decision to it. If the service is not + * available, IllegalStateException is thrown. + */ + @Override + public synchronized boolean authenticated(String username, String password) { + if (nullableUserManager == null) { + logger.warn("Cannot authenticate user '{}', user manager service is missing", username); + throw new IllegalStateException("User manager service is not available"); + } + AuthResultEnum authResult = nullableUserManager.authenticate(username, password); + logger.debug("Authentication result for user '{}' : {}", username, authResult); + return authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC); + } + + @Override + public char[] getPEMAsCharArray() { + return pem.toCharArray(); + } + + @VisibleForTesting + void setNullableUserManager(IUserManager nullableUserManager) { + this.nullableUserManager = nullableUserManager; + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java index a26843fae1..503e764409 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java @@ -20,6 +20,7 @@ import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProviderImpl; import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil.InfixProp; @@ -72,7 +73,7 @@ public class NetconfSSHActivator implements BundleActivator { checkState(StringUtils.isNotBlank(path), "Path to ssh private key is blank. Reconfigure %s", NetconfConfigUtil.getPrivateKeyKey()); String privateKeyPEMString = PEMGenerator.readOrGeneratePK(new File(path)); - final AuthProvider authProvider = new AuthProvider(privateKeyPEMString, bundleContext); + final AuthProvider authProvider = new AuthProviderImpl(privateKeyPEMString, bundleContext); EventLoopGroup bossGroup = new NioEventLoopGroup(); NetconfSSHServer server = NetconfSSHServer.start(sshSocketAddress.getPort(), localAddress, authProvider, bossGroup); diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java index 488c370145..61297835a0 100644 --- a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java @@ -32,6 +32,7 @@ import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication. import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.SshHandler; import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProviderImpl; import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; import org.slf4j.Logger; @@ -58,7 +59,7 @@ public class SSHTest { @Test public void test() throws Exception { new Thread(new EchoServer(), "EchoServer").start(); - AuthProvider authProvider = mock(AuthProvider.class); + AuthProvider authProvider = mock(AuthProviderImpl.class); doReturn(PEMGenerator.generate().toCharArray()).when(authProvider).getPEMAsCharArray(); doReturn(true).when(authProvider).authenticated(anyString(), anyString()); NetconfSSHServer netconfSSHServer = NetconfSSHServer.start(10831, NetconfConfigUtil.getNetconfLocalAddress(), diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/authentication/SSHServerTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/authentication/SSHServerTest.java index 5e368bc566..75d18566ee 100644 --- a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/authentication/SSHServerTest.java +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/authentication/SSHServerTest.java @@ -60,7 +60,7 @@ public class SSHServerTest { try (InputStream is = getClass().getResourceAsStream("/RSA.pk")) { pem = IOUtils.toString(is); } - AuthProvider ap = new AuthProvider(pem, mockedContext); + AuthProviderImpl ap = new AuthProviderImpl(pem, mockedContext); ap.setNullableUserManager(um); EventLoopGroup bossGroup = new NioEventLoopGroup(); NetconfSSHServer server = NetconfSSHServer.start(PORT, NetconfConfigUtil.getNetconfLocalAddress(), diff --git a/opendaylight/netconf/netconf-testtool/pom.xml b/opendaylight/netconf/netconf-testtool/pom.xml new file mode 100644 index 0000000000..ae0bb76832 --- /dev/null +++ b/opendaylight/netconf/netconf-testtool/pom.xml @@ -0,0 +1,143 @@ + + + + + 4.0.0 + + + org.opendaylight.controller + netconf-subsystem + 0.2.5-SNAPSHOT + + + netconf-testtool + ${project.artifactId} + + + + net.sourceforge.argparse4j + argparse4j + 0.4.3 + + + ch.qos.logback + logback-classic + compile + + + ${project.groupId} + netconf-netty-util + + + org.opendaylight.controller + commons.logback_settings + + + org.opendaylight.controller + config-netconf-connector + + + org.opendaylight.controller + netconf-connector-config + + + org.opendaylight.controller + logback-config + + + org.opendaylight.yangtools + mockito-configuration + + + org.slf4j + slf4j-api + + + xmlunit + xmlunit + + + + ${project.groupId} + config-util + + + ${project.groupId} + netconf-api + + + ${project.groupId} + netconf-client + + + ${project.groupId} + netconf-impl + + + ${project.groupId} + netconf-mapping-api + + + ${project.groupId} + netconf-monitoring + + + + ${project.groupId} + netconf-ssh + + + + ${project.groupId} + netty-config-api + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + + + shade + + package + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + org.opendaylight.controller.netconf.test.tool.Main + + + true + executable + + + + + + + + diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/AcceptingAuthProvider.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/AcceptingAuthProvider.java new file mode 100644 index 0000000000..35f2345248 --- /dev/null +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/AcceptingAuthProvider.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.test.tool; + +import java.io.File; +import java.io.IOException; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; +import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; + +class AcceptingAuthProvider implements AuthProvider { + private final String privateKeyPEMString; + + public AcceptingAuthProvider() { + try { + this.privateKeyPEMString = PEMGenerator.readOrGeneratePK(new File("PK")); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public synchronized boolean authenticated(final String username, final String password) { + return true; + } + + @Override + public char[] getPEMAsCharArray() { + return privateKeyPEMString.toCharArray(); + } +} diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/Main.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/Main.java new file mode 100644 index 0000000000..59e9f4c980 --- /dev/null +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/Main.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.test.tool; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.io.Files; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.List; + +import net.sourceforge.argparse4j.ArgumentParsers; +import net.sourceforge.argparse4j.annotation.Arg; +import net.sourceforge.argparse4j.inf.ArgumentParser; +import net.sourceforge.argparse4j.inf.ArgumentParserException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Charsets; +import com.google.common.io.CharStreams; + +public final class Main { + + // TODO add logback config + + // TODO make exi configurable + + private static final Logger LOG = LoggerFactory.getLogger(Main.class); + + static class Params { + + @Arg(dest = "schemas-dir") + public File schemasDir; + + @Arg(dest = "devices-count") + public int deviceCount; + + @Arg(dest = "starting-port") + public int startingPort; + + @Arg(dest = "generate-configs-dir") + public File generateConfigsDir; + + @Arg(dest = "generate-configs-batch-size") + public int generateConfigBatchSize; + + @Arg(dest = "ssh") + public boolean ssh; + + static ArgumentParser getParser() { + final ArgumentParser parser = ArgumentParsers.newArgumentParser("netconf testool"); + parser.addArgument("--devices-count") + .type(Integer.class) + .setDefault(1) + .type(Integer.class) + .help("Number of simulated netconf devices to spin") + .dest("devices-count"); + + parser.addArgument("--schemas-dir") + .type(File.class) + .required(true) + .help("Directory containing yang schemas to describe simulated devices") + .dest("schemas-dir"); + + parser.addArgument("--starting-port") + .type(Integer.class) + .setDefault(17830) + .help("First port for simulated device. Each other device will have previous+1 port number") + .dest("starting-port"); + + parser.addArgument("--generate-configs-batch-size") + .type(Integer.class) + .setDefault(100) + .help("Number of connector configs per generated file") + .dest("generate-configs-batch-size"); + + parser.addArgument("--generate-configs-dir") + .type(File.class) + .help("Directory where initial config files for ODL distribution should be generated") + .dest("generate-configs-dir"); + + parser.addArgument("--ssh") + .type(Boolean.class) + .setDefault(true) + .help("Whether to use ssh for transport or just pure tcp") + .dest("ssh"); + + return parser; + } + + void validate() { + checkArgument(deviceCount > 0, "Device count has to be > 0"); + checkArgument(startingPort > 1024, "Starting port has to be > 1024"); + + checkArgument(schemasDir.exists(), "Schemas dir has to exist"); + checkArgument(schemasDir.isDirectory(), "Schemas dir has to be a directory"); + checkArgument(schemasDir.canRead(), "Schemas dir has to be readable"); + } + } + + public static void main(final String[] args) { + final Params params = parseArgs(args, Params.getParser()); + params.validate(); + + final NetconfDeviceSimulator netconfDeviceSimulator = new NetconfDeviceSimulator(); + try { + final List openDevices = netconfDeviceSimulator.start(params); + if(params.generateConfigsDir != null) { + new ConfigGenerator(params.generateConfigsDir, openDevices).generate(params.ssh, params.generateConfigBatchSize); + } + } catch (final Exception e) { + LOG.error("Unhandled exception", e); + netconfDeviceSimulator.close(); + System.exit(1); + } + + // Block main thread + synchronized (netconfDeviceSimulator) { + try { + netconfDeviceSimulator.wait(); + } catch (final InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + + private static Params parseArgs(final String[] args, final ArgumentParser parser) { + final Params opt = new Params(); + try { + parser.parseArgs(args, opt); + return opt; + } catch (final ArgumentParserException e) { + parser.handleError(e); + } + + System.exit(1); + return null; + } + + private static class ConfigGenerator { + public static final String NETCONF_CONNECTOR_XML = "/initial/99-netconf-connector.xml"; + public static final String NETCONF_CONNECTOR_NAME = "controller-config"; + public static final String NETCONF_CONNECTOR_PORT = "1830"; + public static final String NETCONF_USE_SSH = "false"; + public static final String SIM_DEVICE_SUFFIX = "-sim-device"; + + private final File directory; + private final List openDevices; + + public ConfigGenerator(final File directory, final List openDevices) { + this.directory = directory; + this.openDevices = openDevices; + } + + public void generate(final boolean useSsh, final int batchSize) { + if(directory.exists() == false) { + checkState(directory.mkdirs(), "Unable to create folder %s" + directory); + } + + try(InputStream stream = Main.class.getResourceAsStream(NETCONF_CONNECTOR_XML)) { + checkNotNull(stream, "Cannot load %s", NETCONF_CONNECTOR_XML); + String configBlueprint = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8)); + + // TODO make address configurable + checkState(configBlueprint.contains(NETCONF_CONNECTOR_NAME)); + checkState(configBlueprint.contains(NETCONF_CONNECTOR_PORT)); + checkState(configBlueprint.contains(NETCONF_USE_SSH)); + configBlueprint = configBlueprint.replace(NETCONF_CONNECTOR_NAME, "%s"); + configBlueprint = configBlueprint.replace(NETCONF_CONNECTOR_PORT, "%s"); + configBlueprint = configBlueprint.replace(NETCONF_USE_SSH, "%s"); + + final String before = configBlueprint.substring(0, configBlueprint.indexOf("")); + final String middleBlueprint = configBlueprint.substring(configBlueprint.indexOf(""), configBlueprint.indexOf("") + "".length()); + final String after = configBlueprint.substring(configBlueprint.indexOf("") + "".length()); + + int connectorCount = 0; + Integer batchStart = null; + StringBuilder b = new StringBuilder(); + b.append(before); + + for (final Integer openDevice : openDevices) { + if(batchStart == null) { + batchStart = openDevice; + } + + final String name = String.valueOf(openDevice) + SIM_DEVICE_SUFFIX; + final String configContent = String.format(middleBlueprint, name, String.valueOf(openDevice), String.valueOf(!useSsh)); + b.append(configContent); + connectorCount++; + if(connectorCount == batchSize) { + b.append(after); + Files.write(b.toString(), new File(directory, String.format("simulated-devices_%d-%d.xml", batchStart, openDevice)), Charsets.UTF_8); + connectorCount = 0; + b = new StringBuilder(); + b.append(before); + batchStart = null; + } + } + + // Write remaining + if(connectorCount != 0) { + b.append(after); + Files.write(b.toString(), new File(directory, String.format("simulated-devices_%d-%d.xml", batchStart, openDevices.get(openDevices.size() - 1))), Charsets.UTF_8); + } + + LOG.info("Config files generated in {}", directory); + } catch (final IOException e) { + throw new RuntimeException("Unable to generate config files", e); + } + } + } +} diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/ModuleBuilderCapability.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/ModuleBuilderCapability.java new file mode 100644 index 0000000000..1a68f55e55 --- /dev/null +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/ModuleBuilderCapability.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.test.tool; + +import com.google.common.base.Optional; +import java.util.Date; +import java.util.List; +import org.opendaylight.controller.netconf.confignetconfconnector.util.Util; +import org.opendaylight.controller.netconf.mapping.api.Capability; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder; + +final class ModuleBuilderCapability implements Capability { + private static final Date NO_REVISION = new Date(0); + private final ModuleBuilder input; + private final Optional content; + + public ModuleBuilderCapability(final ModuleBuilder input, final String inputStream) { + this.input = input; + this.content = Optional.of(inputStream); + } + + @Override + public String getCapabilityUri() { + // FIXME capabilities in Netconf-impl need to check for NO REVISION + final String withoutRevision = getModuleNamespace().get() + "?module=" + getModuleName().get(); + return hasRevision() ? withoutRevision + "&revision=" + Util.writeDate(input.getRevision()) : withoutRevision; + } + + @Override + public Optional getModuleNamespace() { + return Optional.of(input.getNamespace().toString()); + } + + @Override + public Optional getModuleName() { + return Optional.of(input.getName()); + } + + @Override + public Optional getRevision() { + return Optional.of(hasRevision() ? QName.formattedRevision(input.getRevision()) : ""); + } + + private boolean hasRevision() { + return !input.getRevision().equals(NO_REVISION); + } + + @Override + public Optional getCapabilitySchema() { + return content; + } + + @Override + public Optional> getLocation() { + return Optional.absent(); + } +} diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java new file mode 100644 index 0000000000..b21c02ac35 --- /dev/null +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.test.tool; + +import com.google.common.base.Charsets; +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.common.io.CharStreams; +import com.google.common.util.concurrent.CheckedFuture; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.util.HashedWheelTimer; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.management.ManagementFactory; +import java.net.Inet4Address; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.UnknownHostException; +import java.util.AbstractMap; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.ExecutionException; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.tree.ParseTreeWalker; +import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession; +import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer; +import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher; +import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory; +import org.opendaylight.controller.netconf.impl.SessionIdProvider; +import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl; +import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService; +import org.opendaylight.controller.netconf.mapping.api.Capability; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperation; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot; +import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService; +import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; +import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource; +import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener; +import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache; +import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils; +import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder; +import org.opendaylight.yangtools.yang.parser.impl.YangParserListenerImpl; +import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository; +import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource; +import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetconfDeviceSimulator implements Closeable { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceSimulator.class); + + public static final int CONNECTION_TIMEOUT_MILLIS = 20000; + + private final NioEventLoopGroup nettyThreadgroup; + private final HashedWheelTimer hashedWheelTimer; + private final List devicesChannels = Lists.newArrayList(); + + public NetconfDeviceSimulator() { + this(new NioEventLoopGroup(), new HashedWheelTimer()); + } + + public NetconfDeviceSimulator(final NioEventLoopGroup eventExecutors, final HashedWheelTimer hashedWheelTimer) { + this.nettyThreadgroup = eventExecutors; + this.hashedWheelTimer = hashedWheelTimer; + } + + private NetconfServerDispatcher createDispatcher(final Map moduleBuilders) { + + final Set capabilities = Sets.newHashSet(Collections2.transform(moduleBuilders.keySet(), new Function() { + @Override + public Capability apply(final ModuleBuilder input) { + return new ModuleBuilderCapability(input, moduleBuilders.get(input)); + } + })); + + final SessionIdProvider idProvider = new SessionIdProvider(); + + final SimulatedOperationProvider simulatedOperationProvider = new SimulatedOperationProvider(idProvider, capabilities); + final NetconfMonitoringOperationService monitoringService = new NetconfMonitoringOperationService(new NetconfMonitoringServiceImpl(simulatedOperationProvider)); + simulatedOperationProvider.addService(monitoringService); + + final DefaultCommitNotificationProducer commitNotifier = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer()); + + final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory( + hashedWheelTimer, simulatedOperationProvider, idProvider, CONNECTION_TIMEOUT_MILLIS, commitNotifier, new LoggingMonitoringService()); + + final NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer( + serverNegotiatorFactory); + return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup); + } + + private Map toModuleBuilders(final Map> sources) { + final Map asts = Maps.transformValues(sources, new Function, ParserRuleContext>() { + @Override + public ParserRuleContext apply(final Map.Entry input) { + return input.getKey().getAST(); + } + }); + final Map> namespaceContext = BuilderUtils.createYangNamespaceContext( + asts.values(), Optional.absent()); + + final ParseTreeWalker walker = new ParseTreeWalker(); + final Map sourceToBuilder = new HashMap<>(); + + for (final Map.Entry entry : asts.entrySet()) { + final ModuleBuilder moduleBuilder = YangParserListenerImpl.create(namespaceContext, entry.getKey().getName(), + walker, entry.getValue()).getModuleBuilder(); + + try(InputStreamReader stream = new InputStreamReader(sources.get(entry.getKey()).getValue().openStream(), Charsets.UTF_8)) { + sourceToBuilder.put(moduleBuilder, CharStreams.toString(stream)); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + return sourceToBuilder; + } + + + public List start(final Main.Params params) { + final Map moduleBuilders = parseSchemasToModuleBuilders(params); + + final NetconfServerDispatcher dispatcher = createDispatcher(moduleBuilders); + + int currentPort = params.startingPort; + + final List openDevices = Lists.newArrayList(); + for (int i = 0; i < params.deviceCount; i++) { + final InetSocketAddress address = getAddress(currentPort); + + final ChannelFuture server; + if(params.ssh) { + final LocalAddress tcpLocalAddress = new LocalAddress(address.toString()); + + server = dispatcher.createLocalServer(tcpLocalAddress); + try { + NetconfSSHServer.start(currentPort, tcpLocalAddress, new AcceptingAuthProvider(), nettyThreadgroup); + } catch (final Exception e) { + LOG.warn("Cannot start simulated device on {}, skipping", address, e); + // Close local server and continue + server.cancel(true); + if(server.isDone()) { + server.channel().close(); + } + continue; + } finally { + currentPort++; + } + + try { + server.get(); + } catch (final InterruptedException e) { + throw new RuntimeException(e); + } catch (final ExecutionException e) { + LOG.warn("Cannot start ssh simulated device on {}, skipping", address, e); + continue; + } + + LOG.debug("Simulated SSH device started on {}", address); + + } else { + server = dispatcher.createServer(address); + currentPort++; + + try { + server.get(); + } catch (final InterruptedException e) { + throw new RuntimeException(e); + } catch (final ExecutionException e) { + LOG.warn("Cannot start tcp simulated device on {}, skipping", address, e); + continue; + } + + LOG.debug("Simulated TCP device started on {}", address); + } + + devicesChannels.add(server.channel()); + openDevices.add(currentPort - 1); + + } + + if(openDevices.size() == params.deviceCount) { + LOG.info("All simulated devices started successfully from port {} to {}", params.startingPort, currentPort); + } else { + LOG.warn("Not all simulated devices started successfully. Started devices ar on ports {}", openDevices); + } + + return openDevices; + } + + private Map parseSchemasToModuleBuilders(final Main.Params params) { + final SharedSchemaRepository consumer = new SharedSchemaRepository("netconf-simulator"); + consumer.registerSchemaSourceListener(TextToASTTransformer.create(consumer, consumer)); + + final Set loadedSources = Sets.newHashSet(); + + consumer.registerSchemaSourceListener(new SchemaSourceListener() { + @Override + public void schemaSourceEncountered(final SchemaSourceRepresentation schemaSourceRepresentation) {} + + @Override + public void schemaSourceRegistered(final Iterable> potentialSchemaSources) { + for (final PotentialSchemaSource potentialSchemaSource : potentialSchemaSources) { + loadedSources.add(potentialSchemaSource.getSourceIdentifier()); + } + } + + @Override + public void schemaSourceUnregistered(final PotentialSchemaSource potentialSchemaSource) {} + }); + + final FilesystemSchemaSourceCache cache = new FilesystemSchemaSourceCache<>(consumer, YangTextSchemaSource.class, params.schemasDir); + consumer.registerSchemaSourceListener(cache); + + final Map> asts = Maps.newHashMap(); + for (final SourceIdentifier loadedSource : loadedSources) { + try { + final CheckedFuture ast = consumer.getSchemaSource(loadedSource, ASTSchemaSource.class); + final CheckedFuture text = consumer.getSchemaSource(loadedSource, YangTextSchemaSource.class); + asts.put(loadedSource, new AbstractMap.SimpleEntry<>(ast.get(), text.get())); + } catch (final InterruptedException e) { + throw new RuntimeException(e); + } catch (final ExecutionException e) { + throw new RuntimeException("Cannot parse schema context", e); + } + } + return toModuleBuilders(asts); + } + + private static InetSocketAddress getAddress(final int port) { + try { + // TODO make address configurable + return new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), port); + } catch (final UnknownHostException e) { + throw new RuntimeException(e); + } + } + + @Override + public void close() { + for (final Channel deviceCh : devicesChannels) { + deviceCh.close(); + } + nettyThreadgroup.shutdownGracefully(); + // close Everything + } + + private static class SimulatedOperationProvider implements NetconfOperationProvider { + private final SessionIdProvider idProvider; + private final Set netconfOperationServices; + + + public SimulatedOperationProvider(final SessionIdProvider idProvider, final Set caps) { + this.idProvider = idProvider; + final SimulatedOperationService simulatedOperationService = new SimulatedOperationService(caps, idProvider.getCurrentSessionId()); + this.netconfOperationServices = Sets.newHashSet(simulatedOperationService); + } + + @Override + public NetconfOperationServiceSnapshot openSnapshot(final String sessionIdForReporting) { + return new SimulatedServiceSnapshot(idProvider, netconfOperationServices); + } + + public void addService(final NetconfOperationService monitoringService) { + netconfOperationServices.add(monitoringService); + } + + private static class SimulatedServiceSnapshot implements NetconfOperationServiceSnapshot { + private final SessionIdProvider idProvider; + private final Set netconfOperationServices; + + public SimulatedServiceSnapshot(final SessionIdProvider idProvider, final Set netconfOperationServices) { + this.idProvider = idProvider; + this.netconfOperationServices = netconfOperationServices; + } + + @Override + public String getNetconfSessionIdForReporting() { + return String.valueOf(idProvider.getCurrentSessionId()); + } + + @Override + public Set getServices() { + return netconfOperationServices; + } + + @Override + public void close() throws Exception {} + } + + static class SimulatedOperationService implements NetconfOperationService { + private final Set capabilities; + private static SimulatedGet sGet; + + public SimulatedOperationService(final Set capabilities, final long currentSessionId) { + this.capabilities = capabilities; + sGet = new SimulatedGet(String.valueOf(currentSessionId)); + } + + @Override + public Set getCapabilities() { + return capabilities; + } + + @Override + public Set getNetconfOperations() { + return Sets.newHashSet(sGet); + } + + @Override + public void close() { + } + + } + } + + private class LoggingMonitoringService implements SessionMonitoringService { + @Override + public void onSessionUp(final NetconfManagementSession session) { + LOG.debug("Session {} established", session); + } + + @Override + public void onSessionDown(final NetconfManagementSession session) { + LOG.debug("Session {} down", session); + } + } + +} diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGet.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGet.java new file mode 100644 index 0000000000..b1938c8332 --- /dev/null +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGet.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.test.tool; + +import com.google.common.base.Optional; +import org.opendaylight.controller.netconf.api.NetconfDocumentedException; +import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; +import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +class SimulatedGet extends AbstractConfigNetconfOperation { + + SimulatedGet(final String netconfSessionIdForReporting) { + super(null, netconfSessionIdForReporting); + } + + @Override + protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException { + return XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.absent()); + } + + @Override + protected String getOperationName() { + return XmlNetconfConstants.GET; + } +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/SendErrorExceptionUtil.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/SendErrorExceptionUtil.java index 4c4ff2fc58..6604834fe4 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/SendErrorExceptionUtil.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/SendErrorExceptionUtil.java @@ -59,12 +59,12 @@ public final class SendErrorExceptionUtil { final NetconfDocumentedException sendErrorException) { try { final Element incommingRpc = incommingDocument.getDocumentElement(); - Preconditions.checkState(incommingRpc.getTagName().equals(XmlNetconfConstants.RPC_KEY), "Missing " - + XmlNetconfConstants.RPC_KEY + " " + "element"); + Preconditions.checkState(incommingRpc.getTagName().equals(XmlNetconfConstants.RPC_KEY), "Missing %s element", + XmlNetconfConstants.RPC_KEY); final Element rpcReply = errorDocument.getDocumentElement(); - Preconditions.checkState(rpcReply.getTagName().equals(XmlNetconfConstants.RPC_REPLY_KEY), "Missing " - + XmlNetconfConstants.RPC_REPLY_KEY + " element"); + Preconditions.checkState(rpcReply.getTagName().equals(XmlNetconfConstants.RPC_REPLY_KEY), "Missing %s element", + XmlNetconfConstants.RPC_REPLY_KEY); final NamedNodeMap incomingAttributes = incommingRpc.getAttributes(); for (int i = 0; i < incomingAttributes.getLength(); i++) { @@ -97,7 +97,7 @@ public final class SendErrorExceptionUtil { @Override public void operationComplete(final ChannelFuture channelFuture) throws Exception { - Preconditions.checkState(channelFuture.isSuccess(), "Unable to send exception {}", sendErrorException, + Preconditions.checkState(channelFuture.isSuccess(), "Unable to send exception %s", sendErrorException, channelFuture.cause()); } } diff --git a/opendaylight/netconf/pom.xml b/opendaylight/netconf/pom.xml index e55ec697ba..b1b410a1fc 100644 --- a/opendaylight/netconf/pom.xml +++ b/opendaylight/netconf/pom.xml @@ -150,5 +150,15 @@ netconf-it + + + testtool + + false + + + netconf-testtool + + 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))