From: Ed Warnicke Date: Mon, 18 Aug 2014 14:52:17 +0000 (+0000) Subject: Merge "Fix precondition formatting" X-Git-Tag: release/helium~278 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=3dd9d7c6da1baaf72f05e1118c0ca47dc16e3c7b;hp=a9fd99f722738fe12d906ab01ce9838b23d875c5;p=controller.git Merge "Fix precondition formatting" --- diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java index d60e608617..abb9f1ae9b 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java @@ -35,7 +35,6 @@ public class ObjectNameUtil { public static final String SERVICE_QNAME_KEY = "serviceQName"; public static final String INSTANCE_NAME_KEY = "instanceName"; public static final String TYPE_KEY = ConfigRegistryConstants.TYPE_KEY; - public static final String TYPE_CONFIG_REGISTRY = ConfigRegistryConstants.TYPE_CONFIG_REGISTRY; public static final String TYPE_CONFIG_TRANSACTION = "ConfigTransaction"; public static final String TYPE_MODULE = "Module"; public static final String TYPE_SERVICE_REFERENCE = "ServiceReference"; @@ -43,6 +42,7 @@ public class ObjectNameUtil { public static final String TRANSACTION_NAME_KEY = "TransactionName"; public static final String REF_NAME_KEY = "RefName"; private static final String REPLACED_QUOTATION_MARK = "\\?"; + public static final String ON_WILDCARD = "*"; public static ObjectName createON(String on) { try { @@ -304,12 +304,9 @@ public class ObjectNameUtil { public static ObjectName createModulePattern(String moduleName, String instanceName) { - if (moduleName == null) { - moduleName = "*"; - } - if (instanceName == null) { - instanceName = "*"; - } + moduleName = moduleName == null ? ON_WILDCARD : moduleName; + instanceName = instanceName == null ? ON_WILDCARD : instanceName; + // do not return object names containing transaction name ObjectName namePattern = ObjectNameUtil .createON(ObjectNameUtil.ON_DOMAIN + ":" @@ -323,6 +320,10 @@ public class ObjectNameUtil { public static ObjectName createModulePattern(String ifcName, String instanceName, String transactionName) { + ifcName = ifcName == null ? ON_WILDCARD : ifcName; + instanceName = instanceName == null ? ON_WILDCARD : instanceName; + transactionName = transactionName == null ? ON_WILDCARD : transactionName; + return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":type=Module," + ObjectNameUtil.MODULE_FACTORY_NAME_KEY + "=" + ifcName + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "=" @@ -332,6 +333,9 @@ public class ObjectNameUtil { public static ObjectName createRuntimeBeanPattern(String moduleName, String instanceName) { + moduleName = moduleName == null ? ON_WILDCARD : moduleName; + instanceName = instanceName == null ? ON_WILDCARD : instanceName; + return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":" + ObjectNameUtil.TYPE_KEY + "=" + ObjectNameUtil.TYPE_RUNTIME_BEAN + "," diff --git a/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/JmxAttributeValidationExceptionTest.java b/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/JmxAttributeValidationExceptionTest.java new file mode 100644 index 0000000000..7a057bbccb --- /dev/null +++ b/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/JmxAttributeValidationExceptionTest.java @@ -0,0 +1,51 @@ +package org.opendaylight.controller.config.api; + +import static org.junit.Assert.assertEquals; + +import com.google.common.collect.Lists; +import org.junit.Before; +import org.junit.Test; + +public class JmxAttributeValidationExceptionTest { + + private JmxAttribute jmxAttribute = new JmxAttribute("attr1"); + private JmxAttribute jmxAttribute2 = new JmxAttribute("attr2"); + + @Before + public void setUp() throws Exception { + + } + + @Test + public void testGetAttributeNames() throws Exception { + + } + + @Test + public void testCheckNotNull() throws Exception { + try { + JmxAttributeValidationException.checkNotNull(false, "message", jmxAttribute); + } catch (JmxAttributeValidationException e) { + assertJmxEx(e, jmxAttribute.getAttributeName() + " " + "message", jmxAttribute); + } + } + + @Test + public void testWrap() throws Exception { + + } + + @Test + public void testCheckCondition() throws Exception { + try { + JmxAttributeValidationException.checkCondition(false, "message", jmxAttribute); + } catch (JmxAttributeValidationException e) { + assertJmxEx(e, jmxAttribute.getAttributeName() + " " + "message", jmxAttribute); + } + } + + private void assertJmxEx(JmxAttributeValidationException e, String message, JmxAttribute... attrNames) { + assertEquals(message, e.getMessage()); + assertEquals(Lists.newArrayList(attrNames), e.getAttributeNames()); + } +} \ No newline at end of file diff --git a/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/ValidationExceptionTest.java b/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/ValidationExceptionTest.java new file mode 100644 index 0000000000..1809e45860 --- /dev/null +++ b/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/ValidationExceptionTest.java @@ -0,0 +1,54 @@ +package org.opendaylight.controller.config.api; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; +import static org.junit.Assert.assertThat; +import static org.junit.matchers.JUnitMatchers.containsString; + +import com.google.common.collect.Lists; +import java.util.Map; +import org.junit.Test; + +public class ValidationExceptionTest { + + private String instance = "instance"; + private final ModuleIdentifier mi = new ModuleIdentifier("module", instance); + private String instance2 = "instance2"; + private final ModuleIdentifier mi2 = new ModuleIdentifier("module", instance2); + private final String message = "ex message"; + private final Exception e = new IllegalStateException(message); + + @Test + public void testCreateFromCollectedValidationExceptions() throws Exception { + ValidationException single = ValidationException.createForSingleException(mi, e); + ValidationException single2 = ValidationException.createForSingleException(mi2, e); + + ValidationException collected = ValidationException.createFromCollectedValidationExceptions(Lists.newArrayList(single, single2)); + + Map> failedMap = collected.getFailedValidations(); + assertEquals(1, failedMap.size()); + assertTrue(failedMap.containsKey("module")); + + Map failedModule = failedMap.get("module"); + assertEquals(2, failedModule.size()); + assertTrue(failedModule.containsKey(instance)); + assertEquals(message, failedModule.get(instance).getMessage()); + assertEquals(message, failedModule.get(instance2).getMessage()); + assertEquals(failedModule.get(instance), failedModule.get(instance2)); + } + + @Test + public void testCreateFromCollectedValidationExceptionsWithDuplicate() throws Exception { + ValidationException single = ValidationException.createForSingleException(mi, e); + ValidationException single2 = ValidationException.createForSingleException(mi, e); + try { + ValidationException.createFromCollectedValidationExceptions(Lists.newArrayList(single, single2)); + } catch (IllegalArgumentException ex) { + // Duplicate exception + assertThat(ex.getMessage(), containsString("Cannot merge")); + return; + } + fail("Duplicate exception should have failed"); + } +} \ No newline at end of file diff --git a/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtilTest.java b/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtilTest.java new file mode 100644 index 0000000000..d3d8469dfb --- /dev/null +++ b/opendaylight/config/config-api/src/test/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtilTest.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.config.api.jmx; + +import static junit.framework.Assert.fail; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import com.google.common.base.Throwables; +import com.google.common.collect.Maps; +import java.util.Map; +import javax.management.ObjectName; +import junit.framework.Assert; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.config.api.ModuleIdentifier; + +public class ObjectNameUtilTest { + + private String moduleName; + private String instanceName; + + @Before + public void setUp() throws Exception { + moduleName = "module"; + instanceName = "instance"; + } + + @Test + public void testServiceReferenceName() throws Exception { + String serviceQName = "(namespace?revision=r)qname"; + String refName = "refName"; + String transaction = "transaction"; + + ObjectName serviceReferenceON = ObjectNameUtil.createTransactionServiceON(transaction, serviceQName, refName); + ObjectNameUtil.checkType(serviceReferenceON, ObjectNameUtil.TYPE_SERVICE_REFERENCE); + + assertFalse(serviceReferenceON.isPattern()); + assertEquals(serviceQName, ObjectNameUtil.getServiceQName(serviceReferenceON)); + assertEquals(refName, ObjectNameUtil.getReferenceName(serviceReferenceON)); + assertEquals(transaction, ObjectNameUtil.getTransactionName(serviceReferenceON)); + assertEquals(ObjectNameUtil.createReadOnlyServiceON(serviceQName, refName), ObjectNameUtil.withoutTransactionName(serviceReferenceON)); + + serviceReferenceON = ObjectNameUtil.createReadOnlyServiceON(serviceQName, refName); + assertFalse(serviceReferenceON.isPattern()); + assertEquals(serviceQName, ObjectNameUtil.getServiceQName(serviceReferenceON)); + assertEquals(refName, ObjectNameUtil.getReferenceName(serviceReferenceON)); + assertEquals(null, ObjectNameUtil.getTransactionName(serviceReferenceON)); + } + + @Test + public void testModuleName() throws Exception { + String txName = "transaction"; + + ObjectName on = ObjectNameUtil.createTransactionModuleON(txName, moduleName, instanceName); + + ObjectNameUtil.checkDomain(on); + ObjectNameUtil.checkType(on, ObjectNameUtil.TYPE_MODULE); + + assertFalse(on.isPattern()); + assertEquals(moduleName, ObjectNameUtil.getFactoryName(on)); + assertEquals(instanceName, ObjectNameUtil.getInstanceName(on)); + assertEquals(txName, ObjectNameUtil.getTransactionName(on)); + assertEquals(4, ObjectNameUtil.getAdditionalProperties(on).size()); + + ObjectName withoutTx = ObjectNameUtil.withoutTransactionName(on); + assertEquals(ObjectNameUtil.createReadOnlyModuleON(moduleName, instanceName), withoutTx); + assertEquals(moduleName, ObjectNameUtil.getFactoryName(withoutTx)); + assertEquals(instanceName, ObjectNameUtil.getInstanceName(withoutTx)); + assertEquals(null, ObjectNameUtil.getTransactionName(withoutTx)); + assertEquals(on, ObjectNameUtil.withTransactionName(withoutTx, txName)); + + ObjectName pattern = ObjectNameUtil.createModulePattern(moduleName, null); + assertPattern(withoutTx, pattern); + pattern = ObjectNameUtil.createModulePattern(moduleName, null, txName); + assertPattern(on, pattern); + } + + private void assertPattern(ObjectName test, ObjectName pattern) { + assertTrue(pattern.isPattern()); + assertTrue(pattern.apply(test)); + } + + @Test + public void testRuntimeBeanName() throws Exception { + + Map properties = Maps.newHashMap(); + properties.put("p1", "value"); + properties.put("p2", "value2"); + + ObjectName on = ObjectNameUtil.createRuntimeBeanName(moduleName, instanceName, properties); + + ObjectNameUtil.checkDomain(on); + ObjectNameUtil.checkTypeOneOf(on, ObjectNameUtil.TYPE_RUNTIME_BEAN); + + assertFalse(on.isPattern()); + assertEquals(moduleName, ObjectNameUtil.getFactoryName(on)); + assertEquals(instanceName, ObjectNameUtil.getInstanceName(on)); + assertEquals(2, ObjectNameUtil.getAdditionalPropertiesOfRuntimeBeanName(on).size()); + assertTrue(ObjectNameUtil.getAdditionalPropertiesOfRuntimeBeanName(on).containsKey("p1")); + assertEquals("value", ObjectNameUtil.getAdditionalPropertiesOfRuntimeBeanName(on).get("p1")); + assertTrue(ObjectNameUtil.getAdditionalProperties(on).containsKey("p2")); + assertEquals("value2", ObjectNameUtil.getAdditionalPropertiesOfRuntimeBeanName(on).get("p2")); + + ObjectName pattern = ObjectNameUtil.createRuntimeBeanPattern(null, instanceName); + assertPattern(on, pattern); + } + + @Test + public void testModuleIdentifier() throws Exception { + ModuleIdentifier mi = new ModuleIdentifier(moduleName, instanceName); + ObjectName on = ObjectNameUtil.createReadOnlyModuleON(mi); + assertEquals(moduleName, ObjectNameUtil.getFactoryName(on)); + assertEquals(instanceName, ObjectNameUtil.getInstanceName(on)); + + assertEquals(mi, ObjectNameUtil.fromON(on, ObjectNameUtil.TYPE_MODULE)); + } + + @Test + public void testChecks() throws Exception { + final ObjectName on = ObjectNameUtil.createON("customDomain", ObjectNameUtil.TYPE_KEY, ObjectNameUtil.TYPE_MODULE); + + assertFailure(new Runnable() { + @Override + public void run() { + ObjectNameUtil.checkTypeOneOf(on, ObjectNameUtil.TYPE_RUNTIME_BEAN, ObjectNameUtil.TYPE_CONFIG_TRANSACTION); + } + }, IllegalArgumentException.class); + + assertFailure(new Runnable() { + @Override + public void run() { + ObjectNameUtil.checkType(on, ObjectNameUtil.TYPE_RUNTIME_BEAN); + } + }, IllegalArgumentException.class); + + assertFailure(new Runnable() { + @Override + public void run() { + ObjectNameUtil.checkDomain(on); + } + }, IllegalArgumentException.class); + } + + private void assertFailure(Runnable test, Class ex) { + try { + test.run(); + } catch(Exception e) { + Assert.assertTrue("Failed with wrong exception: " + Throwables.getStackTraceAsString(e), + e.getClass().isAssignableFrom(ex)); + return; + } + + fail(test + " should have failed on " + ex); + } +} diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java index 720b7197ea..375ef59487 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java @@ -7,6 +7,8 @@ */ package org.opendaylight.controller.config.manager.impl.osgi; +import com.google.common.annotations.VisibleForTesting; +import javax.management.ObjectName; import org.opendaylight.controller.config.api.ConflictingVersionException; import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.jmx.CommitStatus; @@ -17,8 +19,6 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.management.ObjectName; - /** * Every time factory is added or removed, blank transaction is triggered to handle * {@link org.opendaylight.controller.config.spi.ModuleFactory#getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory, org.osgi.framework.BundleContext)} @@ -27,10 +27,29 @@ import javax.management.ObjectName; public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer { private static final Logger logger = LoggerFactory.getLogger(BlankTransactionServiceTracker.class); - private final ConfigRegistryImpl configRegistry; + public static final int DEFAULT_MAX_ATTEMPTS = 10; - public BlankTransactionServiceTracker(ConfigRegistryImpl configRegistry) { - this.configRegistry = configRegistry; + private final BlankTransaction blankTransaction; + private int maxAttempts; + + public BlankTransactionServiceTracker(final ConfigRegistryImpl configRegistry) { + this(new BlankTransaction() { + @Override + public CommitStatus hit() throws ValidationException, ConflictingVersionException { + ObjectName tx = configRegistry.beginConfig(true); + return configRegistry.commitConfig(tx); + } + }); + } + + public BlankTransactionServiceTracker(final BlankTransaction blankTransaction) { + this(blankTransaction, DEFAULT_MAX_ATTEMPTS); + } + + @VisibleForTesting + BlankTransactionServiceTracker(final BlankTransaction blankTx, final int maxAttempts) { + this.blankTransaction = blankTx; + this.maxAttempts = maxAttempts; } @Override @@ -42,13 +61,10 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer< synchronized void blankTransaction() { // race condition check: config-persister might push new configuration while server is starting up. ConflictingVersionException lastException = null; - int maxAttempts = 10; for (int i = 0; i < maxAttempts; i++) { try { // create transaction - boolean blankTransaction = true; - ObjectName tx = configRegistry.beginConfig(blankTransaction); - CommitStatus commitStatus = configRegistry.commitConfig(tx); + CommitStatus commitStatus = blankTransaction.hit(); logger.debug("Committed blank transaction with status {}", commitStatus); return; } catch (ConflictingVersionException e) { @@ -77,4 +93,9 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer< public void removedService(ServiceReference moduleFactoryServiceReference, Object o) { blankTransaction(); } + + @VisibleForTesting + static interface BlankTransaction { + CommitStatus hit() throws ValidationException, ConflictingVersionException; + } } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java index 05ca43c3e2..3015ed229e 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.config.manager.impl.osgi; import static java.lang.String.format; +import com.google.common.annotations.VisibleForTesting; import java.io.InputStream; import java.net.URL; import java.util.List; @@ -70,9 +71,10 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer registerFactory(String factoryClassName, Bundle bundle) { + @VisibleForTesting + protected static ServiceRegistration registerFactory(String factoryClassName, Bundle bundle) { String errorMessage; + Exception ex = null; try { Class clazz = bundle.loadClass(factoryClassName); if (ModuleFactory.class.isAssignableFrom(clazz)) { @@ -86,10 +88,12 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer> getOsgiRegistrationTypes( Class configBeanClass) { - // TODO test with service interface hierarchy Set> serviceInterfaces = getServiceInterfaces(configBeanClass); Set> result = new HashSet<>(); for (Class clazz : serviceInterfaces) { diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java index e84337756e..f1072a76ae 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.config.manager.impl.util; import org.opendaylight.controller.config.spi.ModuleFactory; import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName; +import org.opendaylight.yangtools.yang.common.QName; import org.osgi.framework.BundleContext; import java.util.HashSet; @@ -31,9 +32,7 @@ public class ModuleQNameUtil { inspected = inspected.getSuperclass(); } if (annotation != null) { - // FIXME - String qName = "(" + annotation.namespace() + "?revision=" + annotation.revision() + ")" + annotation.name(); - result.add(qName); + result.add(QName.create(annotation.namespace(), annotation.revision(), annotation.name()).toString()); } } return result; diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java index 8873596642..2df28f0a15 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java @@ -8,6 +8,11 @@ package org.opendaylight.controller.config.manager.impl.util; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.osgi.util.tracker.BundleTracker; @@ -15,12 +20,6 @@ import org.osgi.util.tracker.ServiceTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.List; -import java.util.ListIterator; - -import static com.google.common.base.Preconditions.checkNotNull; - public class OsgiRegistrationUtil { private static final Logger logger = LoggerFactory.getLogger(OsgiRegistrationUtil.class); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTrackerTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTrackerTest.java new file mode 100644 index 0000000000..471c98a676 --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTrackerTest.java @@ -0,0 +1,83 @@ +package org.opendaylight.controller.config.manager.impl.osgi; + +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertSame; +import static junit.framework.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.util.Collections; +import javax.management.ObjectName; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.config.api.ValidationException; +import org.opendaylight.controller.config.api.jmx.CommitStatus; +import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.ServiceReference; + +public class BlankTransactionServiceTrackerTest { + + @Mock + private BlankTransactionServiceTracker.BlankTransaction blankTx; + private BlankTransactionServiceTracker tracker; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn(new CommitStatus(Collections.emptyList(), Collections.emptyList(), Collections.emptyList())).when(blankTx).hit(); + tracker = new BlankTransactionServiceTracker(blankTx); + } + + @Test + public void testBlankTransaction() throws Exception { + tracker.addingService(getMockServiceReference()); + tracker.modifiedService(getMockServiceReference(), null); + tracker.removedService(getMockServiceReference(), null); + verify(blankTx, times(3)).hit(); + } + + @Test + public void testValidationException() throws Exception { + IllegalArgumentException argumentException = new IllegalArgumentException(); + ValidationException validationException = ValidationException.createForSingleException(new ModuleIdentifier("m", "i"), argumentException); + doThrow(validationException).when(blankTx).hit(); + try { + tracker.addingService(getMockServiceReference()); + } catch (Exception e) { + verify(blankTx, times(1)).hit(); + assertNotNull(e.getCause()); + assertSame(validationException, e.getCause()); + return; + } + + fail("Exception should have occurred for validation exception"); + } + + @Test + public void testConflictingException() throws Exception { + int maxAttempts = 2; + tracker = new BlankTransactionServiceTracker(blankTx, maxAttempts); + + final ConflictingVersionException ex = new ConflictingVersionException(); + doThrow(ex).when(blankTx).hit(); + try { + tracker.addingService(getMockServiceReference()); + } catch (Exception e) { + verify(blankTx, times(maxAttempts)).hit(); + return; + } + + fail("Exception should have occurred for conflicting exception"); + } + + private ServiceReference getMockServiceReference() { + return mock(ServiceReference.class); + } +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolverTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolverTest.java new file mode 100644 index 0000000000..dc3deddddc --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolverTest.java @@ -0,0 +1,104 @@ +package org.opendaylight.controller.config.manager.impl.osgi; + +import static junit.framework.Assert.fail; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.matchers.JUnitMatchers.containsString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import com.google.common.collect.Lists; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +public class BundleContextBackedModuleFactoriesResolverTest { + + @Mock + private BundleContext bundleContext; + private BundleContextBackedModuleFactoriesResolver resolver; + private ServiceReference s1; + private ServiceReference s2; + private ModuleFactory f1; + private ModuleFactory f2; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + s1 = getServiceRef(); + s2 = getServiceRef(); + doReturn(Lists.newArrayList(s1, s2)).when(bundleContext).getServiceReferences(ModuleFactory.class, null); + f1 = getMockFactory("f1"); + doReturn(f1).when(bundleContext).getService(s1); + f2 = getMockFactory("f2"); + doReturn(f2).when(bundleContext).getService(s2); + resolver = new BundleContextBackedModuleFactoriesResolver(bundleContext); + } + + private ModuleFactory getMockFactory(String name) { + ModuleFactory mock = mock(ModuleFactory.class); + doReturn(name).when(mock).toString(); + doReturn(name).when(mock).getImplementationName(); + return mock; + } + + private ServiceReference getServiceRef() { + ServiceReference mock = mock(ServiceReference.class); + doReturn("serviceRef").when(mock).toString(); + final Bundle bundle = mock(Bundle.class); + doReturn(bundleContext).when(bundle).getBundleContext(); + doReturn(bundle).when(mock).getBundle(); + return mock; + } + + @Test + public void testGetAllFactories() throws Exception { + Map> allFactories = resolver.getAllFactories(); + assertEquals(2, allFactories.size()); + assertTrue(allFactories.containsKey(f1.getImplementationName())); + assertEquals(f1, allFactories.get(f1.getImplementationName()).getKey()); + assertEquals(bundleContext, allFactories.get(f1.getImplementationName()).getValue()); + assertTrue(allFactories.containsKey(f2.getImplementationName())); + assertEquals(f2, allFactories.get(f2.getImplementationName()).getKey()); + assertEquals(bundleContext, allFactories.get(f2.getImplementationName()).getValue()); + } + + @Test + public void testDuplicateFactories() throws Exception { + doReturn(f1).when(bundleContext).getService(s2); + try { + resolver.getAllFactories(); + } catch (Exception e) { + assertThat(e.getMessage(), containsString(f1.getImplementationName())); + assertThat(e.getMessage(), containsString("unique")); + return; + } + + fail("Should fail with duplicate factory name"); + } + + @Test(expected = NullPointerException.class) + public void testNullFactory() throws Exception { + doReturn(null).when(bundleContext).getService(s2); + resolver.getAllFactories(); + } + + @Test(expected = IllegalStateException.class) + public void testNullFactoryName() throws Exception { + doReturn(null).when(f1).getImplementationName(); + resolver.getAllFactories(); + } + + @Test(expected = NullPointerException.class) + public void testNullBundleName() throws Exception { + doReturn(null).when(s1).getBundle(); + resolver.getAllFactories(); + } +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTrackerTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTrackerTest.java new file mode 100644 index 0000000000..9a3ba64419 --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTrackerTest.java @@ -0,0 +1,76 @@ +package org.opendaylight.controller.config.manager.impl.osgi; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verifyZeroInteractions; + +import com.google.common.util.concurrent.Futures; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.util.tracker.BundleTrackerCustomizer; + +public class ExtensibleBundleTrackerTest { + + @Mock + private BundleContext bundleContext; + @Mock + private Bundle bundle; + @Mock + private BundleEvent bundleEvent; + + @Mock + private BundleTrackerCustomizer primaryTracker; + @Mock + private BundleTrackerCustomizer additionalTracker; + + private ExtensibleBundleTracker extensibleBundleTracker; + private Object primaryValue = new Object(); + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn("bundle").when(bundle).toString(); + doReturn("bundleEvent").when(bundleEvent).toString(); + + doReturn(primaryValue).when(primaryTracker).addingBundle(bundle, bundleEvent); + doNothing().when(primaryTracker).modifiedBundle(bundle, bundleEvent, primaryValue); + doNothing().when(primaryTracker).removedBundle(bundle, bundleEvent, primaryValue); + + doReturn(new Object()).when(additionalTracker).addingBundle(bundle, bundleEvent); + doNothing().when(additionalTracker).modifiedBundle(bundle, bundleEvent, null); + doNothing().when(additionalTracker).removedBundle(bundle, bundleEvent, null); + extensibleBundleTracker = new ExtensibleBundleTracker<>(bundleContext, primaryTracker, additionalTracker); + } + + @Test + public void testAddingBundle() throws Exception { + assertEquals(primaryValue, extensibleBundleTracker.addingBundle(bundle, bundleEvent).get()); + InOrder inOrder = Mockito.inOrder(primaryTracker, additionalTracker); + inOrder.verify(primaryTracker).addingBundle(bundle, bundleEvent); + inOrder.verify(additionalTracker).addingBundle(bundle, bundleEvent); + } + + @Test + public void testRemovedBundle() throws Exception { + extensibleBundleTracker.removedBundle(bundle, bundleEvent, Futures.immediateFuture(primaryValue)); + InOrder inOrder = Mockito.inOrder(primaryTracker, additionalTracker); + inOrder.verify(primaryTracker).removedBundle(bundle, bundleEvent, primaryValue); + inOrder.verify(additionalTracker).removedBundle(bundle, bundleEvent, null); + } + + @Test + public void testRemovedBundleWithEx() throws Exception { + IllegalStateException throwable = new IllegalStateException(); + extensibleBundleTracker.removedBundle(bundle, bundleEvent, Futures.immediateFailedFuture(throwable)); + verifyZeroInteractions(primaryTracker); + verifyZeroInteractions(additionalTracker); + } +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTrackerTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTrackerTest.java new file mode 100644 index 0000000000..5b83412083 --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTrackerTest.java @@ -0,0 +1,193 @@ +package org.opendaylight.controller.config.manager.impl.osgi; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import java.util.Dictionary; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DependencyResolverFactory; +import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; +import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; +import org.opendaylight.controller.config.spi.Module; +import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.ServiceRegistration; + +public class ModuleFactoryBundleTrackerTest { + + @Mock + private Bundle bundle; + @Mock + private BundleContext context; + @Mock + private ServiceRegistration reg; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doAnswer(new Answer() { + @Override + public Object answer(final InvocationOnMock invocation) throws Throwable { + return getClass().getClassLoader().loadClass((String) invocation.getArguments()[0]); + } + }).when(bundle).loadClass(anyString()); + doReturn("mockBundle").when(bundle).toString(); + doReturn(context).when(bundle).getBundleContext(); + doReturn(reg).when(context).registerService(anyString(), anyObject(), any(Dictionary.class)); + } + + @Test + public void testRegisterFactory() throws Exception { + ModuleFactoryBundleTracker.registerFactory(TestingFactory.class.getName(), bundle); + verify(context).registerService(ModuleFactory.class.getName(), TestingFactory.currentInstance, null); + } + + @Test + public void testRegisterFactoryInstantiateEx() throws Exception { + try { + ModuleFactoryBundleTracker.registerFactory(WrongConstructorTestingFactory.class.getName(), bundle); + } catch (Exception e) { + verifyZeroInteractions(context); + assertNotNull(e.getCause()); + assertEquals(InstantiationException.class, e.getCause().getClass()); + return; + } + + fail("Cannot register without proper constructor"); + } + + @Test + public void testRegisterFactoryInstantiateExAccess() throws Exception { + try { + ModuleFactoryBundleTracker.registerFactory(NoAccessConstructorTestingFactory.class.getName(), bundle); + } catch (Exception e) { + verifyZeroInteractions(context); + assertNotNull(e.getCause()); + assertEquals(IllegalAccessException.class, e.getCause().getClass()); + return; + } + + fail("Cannot register without proper constructor"); + } + + @Test + public void testRegisterFactoryNotExtending() throws Exception { + try { + ModuleFactoryBundleTracker.registerFactory(NotExtendingTestingFactory.class.getName(), bundle); + } catch (Exception e) { + verifyZeroInteractions(context); + return; + } + + fail("Cannot register without extend"); + } + + @Test + public void testRegisterFactoryNotExisting() throws Exception { + try { + ModuleFactoryBundleTracker.registerFactory("Unknown class", bundle); + } catch (Exception e) { + verifyZeroInteractions(context); + assertNotNull(e.getCause()); + assertEquals(ClassNotFoundException.class, e.getCause().getClass()); + return; + } + + fail("Cannot register without extend"); + } + + @Mock + private BlankTransactionServiceTracker blankTxTracker; + + @Test + public void testAddingBundle() throws Exception { + final ModuleFactoryBundleTracker tracker = new ModuleFactoryBundleTracker(blankTxTracker); + doReturn(getClass().getResource("/module-factories/module-factory-ok")).when(bundle).getEntry(anyString()); + tracker.addingBundle(bundle, mock(BundleEvent.class)); + verify(context).registerService(ModuleFactory.class.getName(), TestingFactory.currentInstance, null); + } + + @Test + public void testAddingBundleError() throws Exception { + final ModuleFactoryBundleTracker tracker = new ModuleFactoryBundleTracker(blankTxTracker); + doReturn(getClass().getResource("/module-factories/module-factory-fail")).when(bundle).getEntry(anyString()); + try { + tracker.addingBundle(bundle, mock(BundleEvent.class)); + } catch (Exception e) { + verifyZeroInteractions(context); + return; + } + + fail("Cannot register"); + } + + static class WrongConstructorTestingFactory extends TestingFactory { + WrongConstructorTestingFactory(String randomParam) { + } + } + + static class NotExtendingTestingFactory {} + + static class NoAccessConstructorTestingFactory extends TestingFactory { + private NoAccessConstructorTestingFactory() { + } + } + + static class TestingFactory implements ModuleFactory { + + static TestingFactory currentInstance; + + TestingFactory() { + currentInstance = this; + } + + @Override + public String getImplementationName() { + return "Testing"; + } + + @Override + public Module createModule(final String instanceName, final DependencyResolver dependencyResolver, final BundleContext bundleContext) { + throw new UnsupportedOperationException(); + } + + @Override + public Module createModule(final String instanceName, final DependencyResolver dependencyResolver, final DynamicMBeanWithInstance old, final BundleContext bundleContext) throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isModuleImplementingServiceInterface(final Class serviceInterface) { + throw new UnsupportedOperationException(); + } + + @Override + public Set> getImplementedServiceIntefaces() { + throw new UnsupportedOperationException(); + } + + @Override + public Set getDefaultModules(final DependencyResolverFactory dependencyResolverFactory, final BundleContext bundleContext) { + throw new UnsupportedOperationException(); + } + } +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java index 22ea528030..220bef03bc 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelperTest.java @@ -9,20 +9,19 @@ package org.opendaylight.controller.config.manager.impl.util; import static org.junit.Assert.assertEquals; +import com.google.common.collect.Sets; +import java.util.Collections; import java.util.HashSet; import java.util.Set; - import javax.management.MXBean; - import org.junit.Test; import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; +import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingScheduledThreadPoolServiceInterface; import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.yangtools.concepts.Identifiable; -import com.google.common.collect.Sets; - public class InterfacesHelperTest { interface SuperA { @@ -46,10 +45,19 @@ public class InterfacesHelperTest { } + @ServiceInterfaceAnnotation(value = "a", osgiRegistrationType = SuperA.class, namespace = "n", revision = "r", localName = "l") + interface Service extends AbstractServiceInterface{} + @ServiceInterfaceAnnotation(value = "b", osgiRegistrationType = SuperC.class, namespace = "n", revision = "r", localName = "l") + interface SubService extends Service{} + abstract class SubClass extends SuperClass implements SubA, Module { } + abstract class SubClassWithService implements SubService, Module { + + } + @Test public void testGetAllInterfaces() { Set> expected = Sets.> newHashSet(SuperA.class, SuperBMXBean.class, SuperC.class, @@ -58,6 +66,19 @@ public class InterfacesHelperTest { InterfacesHelper.getAllInterfaces(SubClass.class)); } + @Test + public void testGetServiceInterfaces() throws Exception { + assertEquals(Collections.>emptySet(), InterfacesHelper.getServiceInterfaces(SubClass.class)); + assertEquals(Sets.>newHashSet(Service.class, SubService.class), InterfacesHelper.getServiceInterfaces(SubClassWithService.class)); + } + + @Test + public void testGetOsgiRegistrationTypes() throws Exception { + assertEquals(Collections.>emptySet(), InterfacesHelper.getOsgiRegistrationTypes(SubClass.class)); + assertEquals(Sets.>newHashSet(SuperA.class, SuperC.class), + InterfacesHelper.getOsgiRegistrationTypes(SubClassWithService.class)); + } + @Test public void testGetMXInterfaces() { Set> expected = Sets.> newHashSet(SuperBMXBean.class, SubA.class); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/ObjectNameUtilTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/ObjectNameUtilTest.java deleted file mode 100644 index fe322895ab..0000000000 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/ObjectNameUtilTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.config.manager.impl.util; - -import com.google.common.base.Throwables; -import com.google.common.collect.Sets; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.manager.impl.AbstractLockedPlatformMBeanServerTest; - -import javax.management.ObjectName; -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -public class ObjectNameUtilTest extends AbstractLockedPlatformMBeanServerTest { - private Set unregisterONs; - - @Before - public void initUnregisterList() { - unregisterONs = Sets.newHashSet(); - } - - @After - public void unregisterONs() { - Exception lastException = null; - for (ObjectName on : unregisterONs) { - try { - platformMBeanServer.unregisterMBean(on); - } catch (Exception e) { - lastException = e; - } - } - if (lastException != null) { - throw Throwables.propagate(lastException); - } - } - - @Test - public void testQuotation() throws Exception { - String serviceQName = "(namespace?revision=r)qname"; - String refName = "refName"; - String transaction = "transaction"; - ObjectName serviceReferenceON = ObjectNameUtil.createTransactionServiceON(transaction, serviceQName, refName); - assertFalse(serviceReferenceON.isPattern()); - assertEquals(serviceQName, ObjectNameUtil.getServiceQName(serviceReferenceON)); - assertEquals(refName, ObjectNameUtil.getReferenceName(serviceReferenceON)); - assertEquals(transaction, ObjectNameUtil.getTransactionName(serviceReferenceON)); - - serviceReferenceON = ObjectNameUtil.createReadOnlyServiceON(serviceQName, refName); - assertFalse(serviceReferenceON.isPattern()); - assertEquals(serviceQName, ObjectNameUtil.getServiceQName(serviceReferenceON)); - assertEquals(refName, ObjectNameUtil.getReferenceName(serviceReferenceON)); - assertEquals(null, ObjectNameUtil.getTransactionName(serviceReferenceON)); - - } -} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtilTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtilTest.java new file mode 100644 index 0000000000..fb59e3d515 --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtilTest.java @@ -0,0 +1,61 @@ +package org.opendaylight.controller.config.manager.impl.util; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mockito; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.BundleTracker; +import org.osgi.util.tracker.ServiceTracker; + +public class OsgiRegistrationUtilTest { + + @Test + public void testRegisterService() throws Exception { + final BundleContext bundleContext = mock(BundleContext.class); + ServiceRegistration registration = mockServiceRegistration(); + doReturn(registration).when(bundleContext).registerService(String.class, "string", null); + ServiceRegistration registration2 = mockServiceRegistration(); + doReturn(registration2).when(bundleContext).registerService(Object.class, "string", null); + + AutoCloseable aggregatedRegister = OsgiRegistrationUtil.registerService(bundleContext, "string", String.class, Object.class); + aggregatedRegister.close(); + + InOrder inOrder = Mockito.inOrder(registration, registration2); + inOrder.verify(registration2).unregister(); + inOrder.verify(registration).unregister(); + } + + @Test + public void testWrap() throws Exception { + final ServiceRegistration serviceReg = mockServiceRegistration(); + OsgiRegistrationUtil.wrap(serviceReg).close(); + verify(serviceReg).unregister(); + + final BundleTracker tracker = mock(BundleTracker.class); + doNothing().when(tracker).close(); + OsgiRegistrationUtil.wrap(tracker).close(); + verify(tracker).close(); + + final ServiceTracker sTracker = mock(ServiceTracker.class); + doNothing().when(sTracker).close(); + OsgiRegistrationUtil.wrap(sTracker).close(); + verify(sTracker).close(); + } + + private ServiceRegistration mockServiceRegistration() { + ServiceRegistration mock = mock(ServiceRegistration.class); + doNothing().when(mock).unregister(); + return mock; + } + + @Test + public void testAggregate() throws Exception { + + } +} \ No newline at end of file diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java index 0286400d7b..a7024ca39e 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java @@ -9,6 +9,6 @@ package org.opendaylight.controller.config.manager.testingservices.threadpool; import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName; -@ModuleQName(namespace = "namespace", revision = "revision", name = "name") +@ModuleQName(namespace = "namespace", revision = "2012-12-12", name = "name") public abstract class AbstractTestingFixedThreadPoolModuleFactory { } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java index 97d1c63ed2..4ba3dc8939 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java @@ -380,7 +380,8 @@ public class SimpleConfigurationTest extends AbstractConfigTest { @Test public void testQNames() { Set availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames(); - String expected = "(namespace?revision=revision)name"; + String expected = "(namespace?revision=2012-12-12)name"; + assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames); } diff --git a/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-fail b/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-fail new file mode 100644 index 0000000000..fbd810841f --- /dev/null +++ b/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-fail @@ -0,0 +1 @@ +org.opendaylight.controller.config.manager.impl.osgi.ModuleFactoryBundleTrackerTest$NotExtendingTestingFactory \ No newline at end of file diff --git a/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-ok b/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-ok new file mode 100644 index 0000000000..031b622bba --- /dev/null +++ b/opendaylight/config/config-manager/src/test/resources/module-factories/module-factory-ok @@ -0,0 +1 @@ +org.opendaylight.controller.config.manager.impl.osgi.ModuleFactoryBundleTrackerTest$TestingFactory \ No newline at end of file diff --git a/opendaylight/config/netconf-config-dispatcher/pom.xml b/opendaylight/config/netconf-config-dispatcher/pom.xml index b9d218ead1..1e5fcce609 100644 --- a/opendaylight/config/netconf-config-dispatcher/pom.xml +++ b/opendaylight/config/netconf-config-dispatcher/pom.xml @@ -27,6 +27,38 @@ ${project.groupId} netconf-client + + + ${project.groupId} + config-manager + test-jar + test + + + ${project.groupId} + config-manager + test + + + ${project.groupId} + config-util + test + + + ${project.groupId} + netty-threadgroup-config + test + + + ${project.groupId} + netty-timer-config + test + + + org.opendaylight.yangtools + mockito-configuration + test + diff --git a/opendaylight/config/netconf-config-dispatcher/src/test/java/org/opendaylight/controller/config/yang/config/netconf/client/dispatcher/NetconfClientDispatcherModuleTest.java b/opendaylight/config/netconf-config-dispatcher/src/test/java/org/opendaylight/controller/config/yang/config/netconf/client/dispatcher/NetconfClientDispatcherModuleTest.java new file mode 100644 index 0000000000..85477a0237 --- /dev/null +++ b/opendaylight/config/netconf-config-dispatcher/src/test/java/org/opendaylight/controller/config/yang/config/netconf/client/dispatcher/NetconfClientDispatcherModuleTest.java @@ -0,0 +1,102 @@ +package org.opendaylight.controller.config.yang.config.netconf.client.dispatcher; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; +import org.opendaylight.controller.config.api.jmx.CommitStatus; +import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; +import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; +import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; +import org.opendaylight.controller.config.yang.netty.threadgroup.NettyThreadgroupModuleFactory; +import org.opendaylight.controller.config.yang.netty.threadgroup.NettyThreadgroupModuleMXBean; +import org.opendaylight.controller.config.yang.netty.timer.HashedWheelTimerModuleFactory; + +public class NetconfClientDispatcherModuleTest extends AbstractConfigTest{ + + private NetconfClientDispatcherModuleFactory factory; + private final String instanceName = "dispatch"; + + @Before + public void setUp() { + factory = new NetconfClientDispatcherModuleFactory(); + super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,factory, + new NettyThreadgroupModuleFactory(), + new HashedWheelTimerModuleFactory())); + } + + @Test + public void testCreateBean() throws InstanceAlreadyExistsException, ValidationException, ConflictingVersionException { + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + + createInstance(transaction, instanceName, "timer", "thGroup"); + createInstance(transaction, instanceName + 2, "timer2", "thGroup2"); + transaction.validateConfig(); + CommitStatus status = transaction.commit(); + + assertBeanCount(2, factory.getImplementationName()); + assertStatus(status, 2 + 4, 0, 0); + } + + @Test + public void testReusingOldInstance() throws InstanceAlreadyExistsException, ConflictingVersionException, ValidationException { + + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + createInstance(transaction, instanceName, "timer", "thGroup"); + + transaction.commit(); + + transaction = configRegistryClient.createTransaction(); + assertBeanCount(1, factory.getImplementationName()); + CommitStatus status = transaction.commit(); + + assertBeanCount(1, factory.getImplementationName()); + assertStatus(status, 0, 0, 3); + } + + @Test + public void testReconfigure() throws InstanceAlreadyExistsException, ConflictingVersionException, + ValidationException, InstanceNotFoundException { + + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + createInstance(transaction, instanceName, "timer", "thGroup"); + + transaction.commit(); + + transaction = configRegistryClient.createTransaction(); + assertBeanCount(1, factory.getImplementationName()); + NetconfClientDispatcherModuleMXBean mxBean = transaction.newMBeanProxy( + transaction.lookupConfigBean(NetconfClientDispatcherModuleFactory.NAME, instanceName), + NetconfClientDispatcherModuleMXBean.class); + mxBean.setBossThreadGroup(getThreadGroup(transaction, "group2")); + CommitStatus status = transaction.commit(); + + assertBeanCount(1, factory.getImplementationName()); + assertStatus(status, 1, 1, 2); + } + + private ObjectName createInstance(ConfigTransactionJMXClient transaction, String instanceName, String timerName, String threadGroupName) + throws InstanceAlreadyExistsException { + ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), instanceName); + NetconfClientDispatcherModuleMXBean mxBean = transaction.newMBeanProxy(nameCreated, NetconfClientDispatcherModuleMXBean.class); + ObjectName thGroup = getThreadGroup(transaction, threadGroupName); + mxBean.setBossThreadGroup(thGroup); + mxBean.setWorkerThreadGroup(thGroup); + mxBean.setTimer(getTimer(transaction, timerName)); + return nameCreated; + } + + private ObjectName getTimer(ConfigTransactionJMXClient transaction, String name) throws InstanceAlreadyExistsException { + return transaction.createModule(HashedWheelTimerModuleFactory.NAME, name); + } + + private ObjectName getThreadGroup(ConfigTransactionJMXClient transaction, String name) throws InstanceAlreadyExistsException { + ObjectName nameCreated = transaction.createModule(NettyThreadgroupModuleFactory.NAME, name); + NettyThreadgroupModuleMXBean mxBean = transaction.newMXBeanProxy(nameCreated, NettyThreadgroupModuleMXBean.class); + mxBean.setThreadCount(1); + return nameCreated; + } +} diff --git a/opendaylight/config/netty-event-executor-config/src/test/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleTest.java b/opendaylight/config/netty-event-executor-config/src/test/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleTest.java new file mode 100644 index 0000000000..4cc9cc3dde --- /dev/null +++ b/opendaylight/config/netty-event-executor-config/src/test/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.yang.netty.eventexecutor; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.ObjectName; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; +import org.opendaylight.controller.config.api.jmx.CommitStatus; +import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; +import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; +import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; + +public class ImmediateEventExecutorModuleTest extends AbstractConfigTest { + + private GlobalEventExecutorModuleFactory factory; + private final String instanceName = ImmediateEventExecutorModuleFactory.SINGLETON_NAME; + + @Before + public void setUp() { + factory = new GlobalEventExecutorModuleFactory(); + super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,factory)); + } + + @Test + public void testCreateBean() throws InstanceAlreadyExistsException, ValidationException, + ConflictingVersionException { + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + + createInstance(transaction, instanceName); + + transaction.validateConfig(); + CommitStatus status = transaction.commit(); + + assertBeanCount(1, factory.getImplementationName()); + assertStatus(status, 1, 0, 0); + } + + @Test + public void testReusingOldInstance() throws InstanceAlreadyExistsException, ConflictingVersionException, + ValidationException { + + ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); + createInstance(transaction, instanceName); + + transaction.commit(); + + transaction = configRegistryClient.createTransaction(); + assertBeanCount(1, factory.getImplementationName()); + CommitStatus status = transaction.commit(); + + assertBeanCount(1, factory.getImplementationName()); + assertStatus(status, 0, 0, 1); + } + + private ObjectName createInstance(ConfigTransactionJMXClient transaction, String instanceName) + throws InstanceAlreadyExistsException { + ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), instanceName); + transaction.newMBeanProxy(nameCreated, ImmediateEventExecutorModuleMXBean.class); + return nameCreated; + } + +} diff --git a/opendaylight/config/netty-timer-config/src/test/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java b/opendaylight/config/netty-timer-config/src/test/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java similarity index 99% rename from opendaylight/config/netty-timer-config/src/test/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java rename to opendaylight/config/netty-timer-config/src/test/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java index 1b5668b610..5fe5f9496e 100644 --- a/opendaylight/config/netty-timer-config/src/test/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java +++ b/opendaylight/config/netty-timer-config/src/test/java/org/opendaylight/controller/config/yang/netty/timer/HashedWheelTimerModuleTest.java @@ -34,7 +34,7 @@ public class HashedWheelTimerModuleTest extends AbstractConfigTest { public void setUp() { factory = new HashedWheelTimerModuleFactory(); threadFactory = new NamingThreadFactoryModuleFactory(); - super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(factory, threadFactory)); + super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, factory, threadFactory)); } public void testValidationExceptionTickDuration() throws InstanceAlreadyExistsException { diff --git a/opendaylight/md-sal/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 ff3984a548..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 @@ -103,9 +103,10 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable { LOG.debug("Processed {} operations, submitting transaction {}", ops, tx.getIdentifier()); final CheckedFuture result = tx.submit(); - Futures.addCallback(result, new FutureCallback() { + Futures.addCallback(result, new FutureCallback() { @Override - public void onSuccess(Object o) { + public void onSuccess(Void aVoid) { + //NOOP } @Override 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 1b031990ab..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,13 +7,20 @@ */ package org.opendaylight.controller.md.inventory.manager; +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; @@ -27,6 +34,7 @@ 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; @@ -100,21 +108,60 @@ class NodeChangeCommiter implements OpendaylightInventoryListener { LOG.debug("Node updated notification received."); manager.enqueue(new InventoryOperation() { @Override - public void applyOperation(final ReadWriteTransaction 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.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-broker/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index 539f9d45c8..74cceb1cbd 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -67,11 +67,6 @@ org.opendaylight.yangtools binding-generator-impl - - org.opendaylight.yangtools - binding-data-codec - 0.6.2-SNAPSHOT - org.opendaylight.yangtools yang-data-impl diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingAsyncDataBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingAsyncDataBrokerImplModule.java index 93d99c832f..018e26878c 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingAsyncDataBrokerImplModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingAsyncDataBrokerImplModule.java @@ -2,13 +2,14 @@ package org.opendaylight.controller.config.yang.md.sal.binding.impl; import java.util.Collection; import java.util.Collections; -import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; + import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; public class BindingAsyncDataBrokerImplModule extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractBindingAsyncDataBrokerImplModule implements @@ -35,7 +36,7 @@ public class BindingAsyncDataBrokerImplModule extends @Override public java.lang.AutoCloseable createInstance() { Broker domBroker = getDomAsyncBrokerDependency(); - BindingToNormalizedNodeCodec mappingService = getBindingMappingServiceDependency(); + BindingIndependentMappingService mappingService = getBindingMappingServiceDependency(); // FIXME: Switch this to DOM Broker registration which would not require // BundleContext when API are updated. diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java new file mode 100644 index 0000000000..4a4e800078 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.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.config.yang.md.sal.binding.impl; + +import java.util.concurrent.ExecutorService; + +import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; +import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; +import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedDataBrokerImpl; +import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; + +/** +* +*/ +public final class DataBrokerImplModule extends + org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractDataBrokerImplModule { + + public DataBrokerImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, + final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public DataBrokerImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, + final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + final DataBrokerImplModule oldModule, final java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void validate() { + super.validate(); + } + + @Override + public java.lang.AutoCloseable createInstance() { + RootDataBrokerImpl dataBindingBroker; + + + ExecutorService listeningExecutor = SingletonHolder.getDefaultCommitExecutor(); + BindingIndependentMappingService potentialMapping = getMappingServiceDependency(); + if (getDomBrokerDependency() != null && potentialMapping != null) { + + dataBindingBroker = createDomConnectedBroker(listeningExecutor,potentialMapping); + } else { + dataBindingBroker = createStandAloneBroker(listeningExecutor); + } + dataBindingBroker.registerRuntimeBean(getRootRuntimeBeanRegistratorWrapper()); + dataBindingBroker.setNotificationExecutor(SingletonHolder.getDefaultChangeEventExecutor()); + return dataBindingBroker; + } + + + private RootDataBrokerImpl createStandAloneBroker(final ExecutorService listeningExecutor) { + RootDataBrokerImpl broker = new RootDataBrokerImpl(); + broker.setExecutor(listeningExecutor); + return broker; + } + + private RootDataBrokerImpl createDomConnectedBroker(final ExecutorService listeningExecutor, final BindingIndependentMappingService mappingService) { + DomForwardedDataBrokerImpl forwardedBroker = new DomForwardedDataBrokerImpl(); + forwardedBroker.setExecutor(listeningExecutor); + BindingIndependentConnector connector = BindingDomConnectorDeployer.createConnector(mappingService); + getDomBrokerDependency().registerProvider(forwardedBroker, null); + ProviderSession domContext = forwardedBroker.getDomProviderContext(); + forwardedBroker.setConnector(connector); + forwardedBroker.setDomProviderContext(domContext); + forwardedBroker.startForwarding(); + return forwardedBroker; + } + +} 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-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModuleFactory.java similarity index 57% rename from opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/ClusterWrapper.java rename to opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModuleFactory.java index 4ddc2bee85..d3fc5ac215 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/ClusterWrapper.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModuleFactory.java @@ -5,16 +5,13 @@ * 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.md.sal.binding.impl; -package org.opendaylight.controller.remote.rpc.registry; +/** +* +*/ +public class DataBrokerImplModuleFactory extends + org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractDataBrokerImplModuleFactory { -import akka.actor.Address; -import akka.cluster.ClusterEvent; - -public interface ClusterWrapper { - - ClusterEvent.CurrentClusterState getState(); - - Address getAddress(); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/ForwardedCompatibleDataBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/ForwardedCompatibleDataBrokerImplModule.java index 2bc673adff..0ea30f7e66 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/ForwardedCompatibleDataBrokerImplModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/ForwardedCompatibleDataBrokerImplModule.java @@ -7,10 +7,9 @@ */ package org.opendaylight.controller.config.yang.md.sal.binding.impl; -import com.google.common.util.concurrent.ListeningExecutorService; import java.util.Collection; import java.util.Collections; -import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; + import org.opendaylight.controller.md.sal.binding.impl.ForwardedBackwardsCompatibleDataBroker; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; @@ -19,6 +18,9 @@ import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; + +import com.google.common.util.concurrent.ListeningExecutorService; /** * @@ -49,7 +51,7 @@ public final class ForwardedCompatibleDataBrokerImplModule extends @Override public java.lang.AutoCloseable createInstance() { ListeningExecutorService listeningExecutor = SingletonHolder.getDefaultCommitExecutor(); - BindingToNormalizedNodeCodec mappingService = getBindingMappingServiceDependency(); + BindingIndependentMappingService mappingService = getBindingMappingServiceDependency(); Broker domBroker = getDomAsyncBrokerDependency(); ProviderSession session = domBroker.registerProvider(this, null); @@ -58,7 +60,7 @@ public final class ForwardedCompatibleDataBrokerImplModule extends ForwardedBackwardsCompatibleDataBroker dataBroker = new ForwardedBackwardsCompatibleDataBroker(domDataBroker, mappingService, schemaService,listeningExecutor); - dataBroker.setConnector(BindingDomConnectorDeployer.createConnector(mappingService.getLegacy())); + dataBroker.setConnector(BindingDomConnectorDeployer.createConnector(getBindingMappingServiceDependency())); dataBroker.setDomProviderContext(session); return dataBroker; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java index a15b1d746c..b0c2d742e2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java @@ -7,18 +7,12 @@ */ package org.opendaylight.controller.config.yang.md.sal.binding.impl; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; import java.util.Hashtable; import java.util.Map.Entry; import java.util.Set; -import javassist.ClassPool; -import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; + import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; -import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; -import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; import org.opendaylight.yangtools.concepts.Delegator; -import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy; import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -35,6 +29,9 @@ import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + /** * */ @@ -45,14 +42,14 @@ public final class RuntimeMappingModule extends private BundleContext bundleContext; - public RuntimeMappingModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, - final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + public RuntimeMappingModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { super(identifier, dependencyResolver); } - public RuntimeMappingModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, - final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, - final RuntimeMappingModule oldModule, final java.lang.AutoCloseable oldInstance) { + public RuntimeMappingModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + RuntimeMappingModule oldModule, java.lang.AutoCloseable oldInstance) { super(identifier, dependencyResolver, oldModule, oldInstance); } @@ -64,48 +61,41 @@ public final class RuntimeMappingModule extends } @Override - public boolean canReuseInstance(final AbstractRuntimeMappingModule oldModule) { + public boolean canReuseInstance(AbstractRuntimeMappingModule oldModule) { return true; } @Override public java.lang.AutoCloseable createInstance() { - final GeneratedClassLoadingStrategy classLoading = getGlobalClassLoadingStrategy(); - final BindingIndependentMappingService legacyMapping = getGlobalLegacyMappingService(classLoading); - BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(new StreamWriterGenerator(SingletonHolder.JAVASSIST)); - BindingToNormalizedNodeCodec instance = new BindingToNormalizedNodeCodec(classLoading, legacyMapping, codecRegistry); - bundleContext.registerService(SchemaContextListener.class, instance, new Hashtable()); - return instance; - } - private BindingIndependentMappingService getGlobalLegacyMappingService(final GeneratedClassLoadingStrategy classLoading) { - BindingIndependentMappingService potential = tryToReuseGlobalMappingServiceInstance(); - if(potential == null) { - potential = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault(),classLoading); - bundleContext.registerService(SchemaContextListener.class, (SchemaContextListener) potential, new Hashtable()); + RuntimeGeneratedMappingServiceProxy potential = tryToReuseGlobalInstance(); + if(potential != null) { + return potential; } - return potential; - } - private GeneratedClassLoadingStrategy getGlobalClassLoadingStrategy() { - ServiceReference ref = bundleContext.getServiceReference(GeneratedClassLoadingStrategy.class); - return bundleContext.getService(ref); + final RuntimeGeneratedMappingServiceImpl service = new RuntimeGeneratedMappingServiceImpl(SingletonHolder.CLASS_POOL); + bundleContext.registerService(SchemaContextListener.class, service, new Hashtable()); + return service; } - private BindingIndependentMappingService tryToReuseGlobalMappingServiceInstance() { + private RuntimeGeneratedMappingServiceProxy tryToReuseGlobalInstance() { ServiceReference serviceRef = getBundleContext().getServiceReference(BindingIndependentMappingService.class); if(serviceRef == null) { return null; } - return bundleContext.getService(serviceRef); + BindingIndependentMappingService delegate = bundleContext.getService(serviceRef); + if (delegate == null) { + return null; + } + return new RuntimeGeneratedMappingServiceProxy(getBundleContext(),serviceRef,delegate); } private BundleContext getBundleContext() { return bundleContext; } - public void setBundleContext(final BundleContext bundleContext) { + public void setBundleContext(BundleContext bundleContext) { this.bundleContext = bundleContext; } @@ -118,9 +108,9 @@ public final class RuntimeMappingModule extends private ServiceReference reference; private BundleContext bundleContext; - public RuntimeGeneratedMappingServiceProxy(final BundleContext bundleContext, - final ServiceReference serviceRef, - final BindingIndependentMappingService delegate) { + public RuntimeGeneratedMappingServiceProxy(BundleContext bundleContext, + ServiceReference serviceRef, + BindingIndependentMappingService delegate) { this.bundleContext = Preconditions.checkNotNull(bundleContext); this.reference = Preconditions.checkNotNull(serviceRef); this.delegate = Preconditions.checkNotNull(delegate); @@ -132,47 +122,47 @@ public final class RuntimeMappingModule extends } @Override - public CompositeNode toDataDom(final DataObject data) { + public CompositeNode toDataDom(DataObject data) { return delegate.toDataDom(data); } @Override public Entry toDataDom( - final Entry, DataObject> entry) { + Entry, DataObject> entry) { return delegate.toDataDom(entry); } @Override public YangInstanceIdentifier toDataDom( - final org.opendaylight.yangtools.yang.binding.InstanceIdentifier path) { + org.opendaylight.yangtools.yang.binding.InstanceIdentifier path) { return delegate.toDataDom(path); } @Override public DataObject dataObjectFromDataDom( - final org.opendaylight.yangtools.yang.binding.InstanceIdentifier path, - final CompositeNode result) throws DeserializationException { + org.opendaylight.yangtools.yang.binding.InstanceIdentifier path, + CompositeNode result) throws DeserializationException { return delegate.dataObjectFromDataDom(path, result); } @Override - public org.opendaylight.yangtools.yang.binding.InstanceIdentifier fromDataDom(final YangInstanceIdentifier entry) + public org.opendaylight.yangtools.yang.binding.InstanceIdentifier fromDataDom(YangInstanceIdentifier entry) throws DeserializationException { return delegate.fromDataDom(entry); } @Override - public Set getRpcQNamesFor(final Class service) { + public Set getRpcQNamesFor(Class service) { return delegate.getRpcQNamesFor(service); } @Override - public Optional> getRpcServiceClassFor(final String namespace, final String revision) { + public Optional> getRpcServiceClassFor(String namespace, String revision) { return delegate.getRpcServiceClassFor(namespace,revision); } @Override - public DataContainer dataObjectFromDataDom(final Class inputClass, final CompositeNode domInput) { + public DataContainer dataObjectFromDataDom(Class inputClass, CompositeNode domInput) { return delegate.dataObjectFromDataDom(inputClass, domInput); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java index f843b23f9b..e632e6336a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.md.sal.binding.impl; import com.google.common.base.Objects; import com.google.common.base.Optional; + import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -18,6 +19,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; + 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.AsyncDataChangeEvent; @@ -35,28 +37,33 @@ import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public abstract class AbstractForwardedDataBroker implements Delegator, DomForwardedBroker, - SchemaContextListener, AutoCloseable { +public abstract class AbstractForwardedDataBroker implements Delegator, DomForwardedBroker, SchemaContextListener, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(AbstractForwardedDataBroker.class); // The Broker to whom we do all forwarding private final DOMDataBroker domDataBroker; + // Mapper to convert from Binding Independent objects to Binding Aware + // objects + private final BindingIndependentMappingService mappingService; + private final BindingToNormalizedNodeCodec codec; private BindingIndependentConnector connector; private ProviderSession context; private final ListenerRegistration schemaListenerRegistration; - protected AbstractForwardedDataBroker(final DOMDataBroker domDataBroker, final BindingToNormalizedNodeCodec codec, - final SchemaService schemaService) { + protected AbstractForwardedDataBroker(final DOMDataBroker domDataBroker, + final BindingIndependentMappingService mappingService,final SchemaService schemaService) { this.domDataBroker = domDataBroker; - this.codec = codec; + this.mappingService = mappingService; + this.codec = new BindingToNormalizedNodeCodec(mappingService); this.schemaListenerRegistration = schemaService.registerSchemaContextListener(this); } @@ -64,6 +71,10 @@ public abstract class AbstractForwardedDataBroker implements Delegator registerDataChangeListener(final LogicalDatastoreType store, - final InstanceIdentifier path, final DataChangeListener listener, final DataChangeScope triggeringScope) { + final InstanceIdentifier path, final DataChangeListener listener, + final DataChangeScope triggeringScope) { DOMDataChangeListener domDataChangeListener = new TranslatingDataChangeInvoker(store, path, listener, triggeringScope); YangInstanceIdentifier domPath = codec.toNormalized(path); @@ -84,16 +96,23 @@ public abstract class AbstractForwardedDataBroker implements Delegator, DataObject> toBinding(final InstanceIdentifier path, + protected Map, DataObject> toBinding( + InstanceIdentifier path, final Map> normalized) { Map, DataObject> newMap = new HashMap<>(); for (Map.Entry> entry : sortedEntries(normalized)) { try { - Optional, DataObject>> potential = getCodec().toBinding(entry); + Optional, DataObject>> potential = getCodec().toBinding( + entry); if (potential.isPresent()) { Entry, DataObject> binding = potential.get(); newMap.put(binding.getKey(), binding.getValue()); + } else if (entry.getKey().getLastPathArgument() instanceof YangInstanceIdentifier.AugmentationIdentifier) { + DataObject bindingDataObject = getCodec().toBinding(path, entry.getValue()); + if (bindingDataObject != null) { + newMap.put(path, bindingDataObject); + } } } catch (DeserializationException e) { LOG.warn("Failed to transform {}, omitting it", entry, e); @@ -104,7 +123,8 @@ public abstract class AbstractForwardedDataBroker implements Delegator> MAP_ENTRY_COMPARATOR = new Comparator>() { @Override - public int compare(final Entry left, final Entry right) { + public int compare(final Entry left, + final Entry right) { final Iterator li = left.getKey().getPathArguments().iterator(); final Iterator ri = right.getKey().getPathArguments().iterator(); @@ -124,7 +144,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator Iterable> sortedEntries(final Map map) { + private static Iterable> sortedEntries(final Map map) { if (!map.isEmpty()) { ArrayList> entries = new ArrayList<>(map.entrySet()); Collections.sort(entries, MAP_ENTRY_COMPARATOR); @@ -134,7 +154,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator> toBinding(final InstanceIdentifier path, + protected Set> toBinding(InstanceIdentifier path, final Set normalized) { Set> hashSet = new HashSet<>(); for (YangInstanceIdentifier normalizedPath : normalized) { @@ -157,7 +177,12 @@ public abstract class AbstractForwardedDataBroker implements Delegator> of(data)); + + try { + return Optional.fromNullable(getCodec().toBinding(path, data)); + } catch (DeserializationException e) { + return Optional.absent(); + } } private class TranslatingDataChangeInvoker implements DOMDataChangeListener { @@ -175,7 +200,8 @@ public abstract class AbstractForwardedDataBroker implements Delegator> change) { + public void onDataChanged( + final AsyncDataChangeEvent> change) { bindingDataChangeListener.onDataChanged(new TranslatedDataChangeEvent(change, path)); } } @@ -235,7 +261,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator binding) { - return codecRegistry.toYangInstanceIdentifier(binding); + + // Used instance-identifier codec do not support serialization of last + // path + // argument if it is Augmentation (behaviour expected by old datastore) + // in this case, we explicitly check if last argument is augmentation + // to process it separately + if (isAugmentationIdentifier(binding)) { + return toNormalizedAugmented(binding); + } + return toNormalizedImpl(binding); } - @SuppressWarnings({ "unchecked", "rawtypes" }) public Entry> toNormalizedNode( final InstanceIdentifier bindingPath, final DataObject bindingObject) { - return codecRegistry.toNormalizedNode((InstanceIdentifier) bindingPath, bindingObject); + return toNormalizedNode(toBindingEntry(bindingPath, bindingObject)); } public Entry> toNormalizedNode( final Entry, DataObject> binding) { - return toNormalizedNode(binding.getKey(),binding.getValue()); + Entry legacyEntry = bindingToLegacy + .toDataDom(binding); + Entry> normalizedEntry = legacyToNormalized + .toNormalized(legacyEntry); + LOG.trace("Serialization of {}, Legacy Representation: {}, Normalized Representation: {}", binding, + legacyEntry, normalizedEntry); + if (isAugmentation(binding.getKey().getTargetType())) { + + for (DataContainerChild child : ((DataContainerNode) normalizedEntry + .getValue()).getValue()) { + if (child instanceof AugmentationNode) { + ImmutableList childArgs = ImmutableList. builder() + .addAll(normalizedEntry.getKey().getPathArguments()).add(child.getIdentifier()).build(); + org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier childPath = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier + .create(childArgs); + return toDOMEntry(childPath, child); + } + } + + } + return normalizedEntry; + } /** @@ -75,13 +125,109 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener,AutoC public Optional> toBinding( final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized) throws DeserializationException { + + PathArgument lastArgument = Iterables.getLast(normalized.getPathArguments()); + // Used instance-identifier codec do not support serialization of last + // path + // argument if it is AugmentationIdentifier (behaviour expected by old + // datastore) + // in this case, we explicitly check if last argument is augmentation + // to process it separately + if (lastArgument instanceof AugmentationIdentifier) { + return toBindingAugmented(normalized); + } + return toBindingImpl(normalized); + } + + private Optional> toBindingAugmented( + final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized) + throws DeserializationException { + Optional> potential = toBindingImpl(normalized); + // Shorthand check, if codec already supports deserialization + // of AugmentationIdentifier we will return + if (potential.isPresent() && isAugmentationIdentifier(potential.get())) { + return potential; + } + + int normalizedCount = getAugmentationCount(normalized); + AugmentationIdentifier lastArgument = (AugmentationIdentifier) Iterables.getLast(normalized.getPathArguments()); + + // Here we employ small trick - Binding-aware Codec injects an pointer + // to augmentation class + // if child is referenced - so we will reference child and then shorten + // path. + LOG.trace("Looking for candidates to match {}", normalized); + for (QName child : lastArgument.getPossibleChildNames()) { + org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier childPath = normalized.node(child); + try { + if (isNotRepresentable(childPath)) { + LOG.trace("Path {} is not BI-representable, skipping it", childPath); + continue; + } + } catch (DataNormalizationException e) { + LOG.warn("Failed to denormalize path {}, skipping it", childPath, e); + continue; + } + + Optional> baId = toBindingImpl(childPath); + if (!baId.isPresent()) { + LOG.debug("No binding-aware identifier found for path {}, skipping it", childPath); + continue; + } + + InstanceIdentifier potentialPath = shortenToLastAugment(baId.get()); + int potentialAugmentCount = getAugmentationCount(potentialPath); + if (potentialAugmentCount == normalizedCount) { + LOG.trace("Found matching path {}", potentialPath); + return Optional.> of(potentialPath); + } + + LOG.trace("Skipping mis-matched potential path {}", potentialPath); + } + + LOG.trace("Failed to find augmentation matching {}", normalized); + return Optional.absent(); + } + + private Optional> toBindingImpl( + final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized) + throws DeserializationException { + org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier legacyPath; + try { - return Optional.>of(codecRegistry.fromYangInstanceIdentifier(normalized)); - } catch (IllegalArgumentException e) { - return Optional.absent(); + if (isNotRepresentable(normalized)) { + return Optional.absent(); + } + legacyPath = legacyToNormalized.toLegacy(normalized); + } catch (DataNormalizationException e) { + throw new IllegalStateException("Could not denormalize path.", e); + } + LOG.trace("InstanceIdentifier Path Deserialization: Legacy representation {}, Normalized representation: {}", + legacyPath, normalized); + return Optional.> of(bindingToLegacy.fromDataDom(legacyPath)); + } + + private boolean isNotRepresentable(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized) + throws DataNormalizationException { + DataNormalizationOperation op = findNormalizationOperation(normalized); + if (op.isMixin() && op.getIdentifier() instanceof NodeIdentifier) { + return true; + } + if (op.isLeaf()) { + return true; } + return false; } + private DataNormalizationOperation findNormalizationOperation( + final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized) + throws DataNormalizationException { + DataNormalizationOperation current = legacyToNormalized.getRootOperation(); + for (PathArgument arg : normalized.getPathArguments()) { + current = current.getChild(arg); + } + return current; + } private static final Entry, DataObject> toBindingEntry( final org.opendaylight.yangtools.yang.binding.InstanceIdentifier key, @@ -90,19 +236,45 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener,AutoC key, value); } + private static final Entry> toDOMEntry( + final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier key, final NormalizedNode value) { + return new SimpleEntry>(key, + value); + } + + public DataObject toBinding(final InstanceIdentifier path, final NormalizedNode normalizedNode) + throws DeserializationException { + CompositeNode legacy = null; + if (isAugmentationIdentifier(path) && normalizedNode instanceof AugmentationNode) { + QName augIdentifier = BindingReflections.findQName(path.getTargetType()); + ContainerNode virtualNode = Builders.containerBuilder() // + .withNodeIdentifier(new NodeIdentifier(augIdentifier)) // + .withChild((DataContainerChild) normalizedNode) // + .build(); + legacy = (CompositeNode) DataNormalizer.toLegacy(virtualNode); + } else { + legacy = (CompositeNode) DataNormalizer.toLegacy(normalizedNode); + } + + return bindingToLegacy.dataObjectFromDataDom(path, legacy); + } + public DataNormalizer getDataNormalizer() { return legacyToNormalized; } - @SuppressWarnings("unchecked") public Optional, DataObject>> toBinding( final Entry> normalized) throws DeserializationException { - try { - @SuppressWarnings("rawtypes") - Entry binding = codecRegistry.fromNormalizedNode(normalized.getKey(), normalized.getValue()); - return Optional., DataObject>>fromNullable(binding); - } catch (IllegalArgumentException e) { + Optional> potentialPath = toBinding(normalized.getKey()); + if (potentialPath.isPresent()) { + InstanceIdentifier bindingPath = potentialPath.get(); + DataObject bindingData = toBinding(bindingPath, normalized.getValue()); + if (bindingData == null) { + LOG.warn("Failed to deserialize {} to Binding format. Binding path is: {}", normalized, bindingPath); + } + return Optional.of(toBindingEntry(bindingPath, bindingData)); + } else { return Optional.absent(); } } @@ -110,11 +282,269 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener,AutoC @Override public void onGlobalContextUpdated(final SchemaContext arg0) { legacyToNormalized = new DataNormalizer(arg0); - codecRegistry.onBindingRuntimeContextUpdated(BindingRuntimeContext.create(classLoadingStrategy, arg0)); } + private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalizedAugmented( + final InstanceIdentifier augPath) { + org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier processed = toNormalizedImpl(augPath); + // If used instance identifier codec added supports for deserialization + // of last AugmentationIdentifier we will just reuse it + if (isAugmentationIdentifier(processed)) { + return processed; + } + Optional additionalSerialized; + additionalSerialized = toNormalizedAugmentedUsingChildContainers(augPath, processed); + + if (additionalSerialized.isPresent()) { + return additionalSerialized.get(); + } + additionalSerialized = toNormalizedAugmentedUsingChildLeafs(augPath, processed); + if (additionalSerialized.isPresent()) { + return additionalSerialized.get(); + } + throw new IllegalStateException("Unabled to construct augmentation identfier for " + augPath); + } + + /** + * Tries to find correct augmentation identifier using children leafs + * + * This method uses normalized Instance Identifier of parent node to fetch + * schema and {@link BindingReflections#getModuleInfo(Class)} to learn about + * augmentation namespace, specificly, in which module it was defined. + * + * Then it uses it to filter all available augmentations for parent by + * module. After that it walks augmentations in particular module and + * pick-up first which at least one leaf name matches supplied augmentation. + * We could do this safely since YANG explicitly states that no any existing + * augmentations must differ in leaf fully qualified names. + * + * + * @param augPath + * Binding Aware Path which ends with augment + * @param parentPath + * Processed path + * @return + */ + private Optional toNormalizedAugmentedUsingChildLeafs( + final InstanceIdentifier augPath, + final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) { + try { + DataNormalizationOperation parentOp = legacyToNormalized.getOperation(parentPath); + if(!parentOp.getDataSchemaNode().isPresent()) { + return Optional.absent(); + } + DataSchemaNode parentSchema = parentOp.getDataSchemaNode().get(); + if (parentSchema instanceof AugmentationTarget) { + Set augmentations = ((AugmentationTarget) parentSchema).getAvailableAugmentations(); + LOG.info("Augmentations for {}, {}", augPath, augmentations); + Optional schema = findAugmentation(augPath.getTargetType(), augmentations); + if (schema.isPresent()) { + AugmentationIdentifier augmentationIdentifier = DataNormalizationOperation + .augmentationIdentifierFrom(schema.get()); + return Optional.of(parentPath.node(augmentationIdentifier)); + } + } + } catch (DataNormalizationException e) { + throw new IllegalArgumentException(e); + } + return Optional.absent(); + } + + /** + * Creates instance identifier for augmentation child, tries to serialize it + * Instance Identifier is then shortened to last augmentation. + * + * This is for situations, where underlying codec is implementing hydrogen + * style DOM APIs (which did not supported {@link AugmentationIdentifier}.) + * + * @param augPath + * @param parentPath + * Path to parent node + * @return + */ + @SuppressWarnings("rawtypes") + private Optional toNormalizedAugmentedUsingChildContainers( + final InstanceIdentifier augPath, + final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) { + for (Class augChild : BindingReflections.getChildrenClasses(augPath.getTargetType())) { + @SuppressWarnings("unchecked") + InstanceIdentifier childPath = augPath.child(augChild); + org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized = toNormalizedImpl(childPath); + org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier potentialDiscovered = shortenToLastAugmentation( + normalized, parentPath); + if (potentialDiscovered != null) { + return Optional.of(potentialDiscovered); + } + } + return Optional.absent(); + } + + private Optional findAugmentation(final Class targetType, + final Set augmentations) { + YangModuleInfo moduleInfo; + try { + moduleInfo = BindingReflections.getModuleInfo(targetType); + } catch (Exception e) { + throw new IllegalStateException(e); + } + Iterable filtered = filteredByModuleInfo(augmentations, + BindingReflections.getModuleQName(moduleInfo).getModule()); + filtered.toString(); + Set targetTypeGetters = getYangModeledGetters(targetType); + for (AugmentationSchema schema : filtered) { + for (DataSchemaNode child : schema.getChildNodes()) { + String getterName = "get" + BindingMapping.getClassName(child.getQName()); + if (targetTypeGetters.contains(getterName)) { + return Optional.of(schema); + } + } + } + return Optional.absent(); + } + + private static Iterable filteredByModuleInfo(final Iterable augmentations, + final QNameModule module) { + return Iterables.filter(augmentations, new Predicate() { + @Override + public boolean apply(final AugmentationSchema schema) { + final Collection childNodes = schema.getChildNodes(); + return !childNodes.isEmpty() && module.equals(Iterables.get(childNodes, 0).getQName().getModule()); + } + }); + } + + public static final Set getYangModeledGetters(final Class targetType) { + HashSet ret = new HashSet(); + for (Method method : targetType.getMethods()) { + if (isYangModeledGetter(method)) { + ret.add(method.getName()); + } + } + return ret; + } + + /** + * + * Returns true if supplied method represent getter for YANG modeled value + * + * @param method + * Method to be tested + * @return true if method represent getter for YANG Modeled value. + */ + private static final boolean isYangModeledGetter(final Method method) { + return !method.getName().equals("getClass") && !method.getName().equals("getImplementedInterface") + && method.getName().startsWith("get") && method.getParameterTypes().length == 0; + } + + private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier shortenToLastAugmentation( + final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized, + final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) { + int parentSize = Iterables.size(parentPath.getPathArguments()); + int position = 0; + int foundPosition = -1; + for (PathArgument arg : normalized.getPathArguments()) { + position++; + if (arg instanceof AugmentationIdentifier) { + foundPosition = position; + } + } + if (foundPosition > 0 && foundPosition > parentSize) { + Iterable shortened = Iterables.limit(normalized.getPathArguments(), foundPosition); + return org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.create(shortened); + } + return null; + } + + private InstanceIdentifier shortenToLastAugment( + final InstanceIdentifier binding) { + int position = 0; + int foundPosition = -1; + for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : binding.getPathArguments()) { + position++; + if (isAugmentation(arg.getType())) { + foundPosition = position; + } + } + return InstanceIdentifier.create(Iterables.limit(binding.getPathArguments(), foundPosition)); + } + + private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalizedImpl( + final InstanceIdentifier binding) { + final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier legacyPath = bindingToLegacy + .toDataDom(binding); + final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized = legacyToNormalized + .toNormalized(legacyPath); + return normalized; + } + + private static boolean isAugmentation(final Class type) { + return Augmentation.class.isAssignableFrom(type); + } + + private static boolean isAugmentationIdentifier(final InstanceIdentifier potential) { + return Augmentation.class.isAssignableFrom(potential.getTargetType()); + } + + private boolean isAugmentationIdentifier(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier processed) { + return Iterables.getLast(processed.getPathArguments()) instanceof AugmentationIdentifier; + } + + private static int getAugmentationCount(final InstanceIdentifier potential) { + int count = 0; + for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : potential.getPathArguments()) { + if (isAugmentation(arg.getType())) { + count++; + } + + } + return count; + } + + private static int getAugmentationCount(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier potential) { + int count = 0; + for (PathArgument arg : potential.getPathArguments()) { + if (arg instanceof AugmentationIdentifier) { + count++; + } + } + return count; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) public Function>, Optional> deserializeFunction(final InstanceIdentifier path) { - return codecRegistry.deserializeFunction(path); + return new DeserializeFunction(this, path); + } + + private static class DeserializeFunction implements Function>, Optional> { + + private final BindingToNormalizedNodeCodec codec; + private final InstanceIdentifier path; + + public DeserializeFunction(final BindingToNormalizedNodeCodec codec, final InstanceIdentifier path) { + super(); + this.codec = Preconditions.checkNotNull(codec, "Codec must not be null"); + this.path = Preconditions.checkNotNull(path, "Path must not be null"); + } + + @SuppressWarnings("rawtypes") + @Nullable + @Override + public Optional apply(@Nullable final Optional> normalizedNode) { + if (normalizedNode.isPresent()) { + final DataObject dataObject; + try { + dataObject = codec.toBinding(path, normalizedNode.get()); + } catch (DeserializationException e) { + LOG.warn("Failed to create dataobject from node {}", normalizedNode.get(), e); + throw new IllegalStateException("Failed to create dataobject", e); + } + + if (dataObject != null) { + return Optional.of(dataObject); + } + } + return Optional.absent(); + } } /** @@ -136,13 +566,4 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener,AutoC } return currentOp.createDefault(path.getLastPathArgument()); } - - public BindingIndependentMappingService getLegacy() { - return bindingToLegacy; - } - - @Override - public void close() throws Exception { - // NOOP Intentionally - } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java index 52e114b0ea..237d9678f9 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java @@ -7,12 +7,6 @@ */ package org.opendaylight.controller.md.sal.binding.impl; -import com.google.common.base.Function; -import com.google.common.util.concurrent.AsyncFunction; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListeningExecutorService; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -23,6 +17,7 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; + import org.opendaylight.controller.md.sal.common.api.RegistrationListener; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; @@ -49,9 +44,17 @@ import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Function; +import com.google.common.util.concurrent.AsyncFunction; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; + @SuppressWarnings("deprecation") public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDataBroker implements DataProviderService, AutoCloseable { @@ -61,7 +64,7 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat private final ListeningExecutorService executorService; public ForwardedBackwardsCompatibleDataBroker(final DOMDataBroker domDataBroker, - final BindingToNormalizedNodeCodec mappingService, final SchemaService schemaService,final ListeningExecutorService executor) { + final BindingIndependentMappingService mappingService, final SchemaService schemaService,final ListeningExecutorService executor) { super(domDataBroker, mappingService,schemaService); executorService = executor; LOG.info("ForwardedBackwardsCompatibleBroker started."); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBindingDataBroker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBindingDataBroker.java index ef66d80ed4..6359b60684 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBindingDataBroker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBindingDataBroker.java @@ -16,6 +16,7 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; /** * The DataBrokerImpl simply defers to the DOMDataBroker for all its operations. @@ -29,8 +30,8 @@ import org.opendaylight.controller.sal.core.api.model.SchemaService; */ public class ForwardedBindingDataBroker extends AbstractForwardedDataBroker implements DataBroker { - public ForwardedBindingDataBroker(final DOMDataBroker domDataBroker, final BindingToNormalizedNodeCodec codec, final SchemaService schemaService) { - super(domDataBroker, codec,schemaService); + public ForwardedBindingDataBroker(final DOMDataBroker domDataBroker, final BindingIndependentMappingService mappingService, final SchemaService schemaService) { + super(domDataBroker, mappingService,schemaService); } @Override diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java index f037e679be..1ec4aa2d30 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java @@ -7,10 +7,6 @@ */ package org.opendaylight.controller.sal.binding.codegen.impl; -import com.google.common.util.concurrent.ForwardingBlockingQueue; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; -import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -20,19 +16,24 @@ import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; + import javassist.ClassPool; + import org.apache.commons.lang3.StringUtils; import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator; import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory; -import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.util.concurrent.ForwardingBlockingQueue; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + public class SingletonHolder { private static final Logger logger = LoggerFactory.getLogger(SingletonHolder.class); public static final ClassPool CLASS_POOL = ClassPool.getDefault(); - public static final JavassistUtils JAVASSIST = JavassistUtils.forClassPool(CLASS_POOL); public static final org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator RPC_GENERATOR_IMPL = new org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator( CLASS_POOL); public static final RuntimeCodeGenerator RPC_GENERATOR = RPC_GENERATOR_IMPL; diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootDataBrokerImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootDataBrokerImpl.java new file mode 100644 index 0000000000..a1cae266c1 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootDataBrokerImpl.java @@ -0,0 +1,50 @@ +/* + * 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.sal.binding.impl; + +import org.opendaylight.controller.config.yang.md.sal.binding.impl.Data; +import org.opendaylight.controller.config.yang.md.sal.binding.impl.DataBrokerImplRuntimeMXBean; +import org.opendaylight.controller.config.yang.md.sal.binding.impl.DataBrokerImplRuntimeRegistration; +import org.opendaylight.controller.config.yang.md.sal.binding.impl.DataBrokerImplRuntimeRegistrator; +import org.opendaylight.controller.config.yang.md.sal.binding.impl.Transactions; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; + +public class RootDataBrokerImpl extends DataBrokerImpl implements DataBrokerImplRuntimeMXBean { + + private final Transactions transactions = new Transactions(); + private final Data data = new Data(); + private BindingIndependentConnector bindingIndependentConnector; + private DataBrokerImplRuntimeRegistration runtimeBeanRegistration; + + public BindingIndependentConnector getBindingIndependentConnector() { + return bindingIndependentConnector; + } + + public Transactions getTransactions() { + transactions.setCreated(getCreatedTransactionsCount().get()); + transactions.setSubmitted(getSubmittedTransactionsCount().get()); + transactions.setSuccessful(getFinishedTransactionsCount().get()); + transactions.setFailed(getFailedTransactionsCount().get()); + return transactions; + } + + @Override + public Data getData() { + data.setTransactions(getTransactions()); + return data; + } + + public void setBindingIndependentConnector(BindingIndependentConnector runtimeMapping) { + this.bindingIndependentConnector = runtimeMapping; + } + + public void registerRuntimeBean(DataBrokerImplRuntimeRegistrator rootRegistrator) { + runtimeBeanRegistration = rootRegistrator.register(this); + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardedDataBrokerImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardedDataBrokerImpl.java new file mode 100644 index 0000000000..3d0e4deb65 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardedDataBrokerImpl.java @@ -0,0 +1,56 @@ +/* + * 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.sal.binding.impl.forward; + +import java.util.Collection; +import java.util.Collections; + +import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; +import org.opendaylight.controller.sal.core.api.Provider; +import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; + +public class DomForwardedDataBrokerImpl extends RootDataBrokerImpl implements Provider, DomForwardedBroker { + + private BindingIndependentConnector connector; + private ProviderSession domProviderContext; + + public void setConnector(BindingIndependentConnector connector) { + this.connector = connector; + } + + @Override + public void onSessionInitiated(ProviderSession session) { + this.setDomProviderContext(session); + } + + @Override + public Collection getProviderFunctionality() { + return Collections.emptySet(); + } + + @Override + public BindingIndependentConnector getConnector() { + return connector; + } + + @Override + public ProviderSession getDomProviderContext() { + return domProviderContext; + } + + public void setDomProviderContext(ProviderSession domProviderContext) { + this.domProviderContext = domProviderContext; + } + + @Override + public void startForwarding() { + BindingDomConnectorDeployer.startDataForwarding(getConnector(), this, getDomProviderContext()); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/yang/opendaylight-binding-broker-impl.yang b/opendaylight/md-sal/sal-binding-broker/src/main/yang/opendaylight-binding-broker-impl.yang index aec2723591..cee4b1efb3 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/yang/opendaylight-binding-broker-impl.yang +++ b/opendaylight/md-sal/sal-binding-broker/src/main/yang/opendaylight-binding-broker-impl.yang @@ -18,9 +18,10 @@ module opendaylight-sal-binding-broker-impl { identity binding-dom-mapping-service { base config:service-type; - config:java-class "org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec"; + config:java-class "org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService"; } + identity binding-broker-impl { base config:module-type; config:provided-service sal:binding-broker-osgi-registry; @@ -28,6 +29,13 @@ module opendaylight-sal-binding-broker-impl { config:java-name-prefix BindingBrokerImpl; } + identity binding-data-broker { + base config:module-type; + config:provided-service sal:binding-data-broker; + config:provided-service sal:binding-data-consumer-broker; + config:java-name-prefix DataBrokerImpl; + } + identity binding-data-compatible-broker { base config:module-type; config:provided-service sal:binding-data-broker; @@ -123,6 +131,29 @@ module opendaylight-sal-binding-broker-impl { } } + augment "/config:modules/config:module/config:configuration" { + case binding-data-broker { + when "/config:modules/config:module/config:type = 'binding-data-broker'"; + container dom-broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity dom:dom-broker-osgi-registry; + } + } + } + + container mapping-service { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity binding-dom-mapping-service; + } + } + } + } + } + augment "/config:modules/config:module/config:configuration" { case binding-data-compatible-broker { when "/config:modules/config:module/config:type = 'binding-data-compatible-broker'"; @@ -147,6 +178,14 @@ module opendaylight-sal-binding-broker-impl { } } + augment "/config:modules/config:module/config:state" { + case binding-data-broker { + when "/config:modules/config:module/config:type = 'binding-data-broker'"; + container data { + uses common:data-state; + } + } + } augment "/config:modules/config:module/config:state" { case binding-rpc-broker { when "/config:modules/config:module/config:type = 'binding-rpc-broker'"; diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java index 815fc45259..fd0a169694 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java @@ -1,8 +1,8 @@ package org.opendaylight.controller.md.sal.binding.impl.test; import static org.junit.Assert.assertTrue; - import javassist.ClassPool; + import org.junit.Test; import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; import org.opendaylight.controller.md.sal.binding.test.AbstractSchemaAwareTest; @@ -11,11 +11,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controll import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey; -import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; -import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; -import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy; import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl; -import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; @@ -38,9 +34,7 @@ public class BindingNormalizedCodecTest extends AbstractSchemaAwareTest { @Override protected void setupWithSchema(final SchemaContext context) { mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault()); - StreamWriterGenerator streamWriter = new StreamWriterGenerator(JavassistUtils.forClassPool(ClassPool.getDefault())); - BindingNormalizedNodeCodecRegistry registry = new BindingNormalizedNodeCodecRegistry(streamWriter); - codec = new BindingToNormalizedNodeCodec(GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), mappingService, registry); + codec = new BindingToNormalizedNodeCodec(mappingService); mappingService.onGlobalContextUpdated(context); codec.onGlobalContextUpdated(context); }; diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java index 106fcea0e9..60eec55ca5 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java @@ -7,14 +7,9 @@ */ package org.opendaylight.controller.md.sal.binding.test; -import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; - import javassist.ClassPool; import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; import org.opendaylight.controller.md.sal.binding.impl.ForwardedBackwardsCompatibleDataBroker; import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; @@ -24,22 +19,20 @@ import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; import org.opendaylight.controller.sal.binding.test.util.MockSchemaService; import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.opendaylight.controller.sal.core.spi.data.DOMStore; -import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator; -import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; -import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; -import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy; import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl; -import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + public class DataBrokerTestCustomizer { private DOMDataBroker domDataBroker; private final RuntimeGeneratedMappingServiceImpl mappingService; private final MockSchemaService schemaService; private ImmutableMap datastores; - private final BindingToNormalizedNodeCodec bindingToNormalized ; public ImmutableMap createDatastores() { return ImmutableMap.builder() @@ -50,13 +43,7 @@ public class DataBrokerTestCustomizer { public DataBrokerTestCustomizer() { schemaService = new MockSchemaService(); - ClassPool pool = ClassPool.getDefault(); - mappingService = new RuntimeGeneratedMappingServiceImpl(pool); - DataObjectSerializerGenerator generator = StreamWriterGenerator.create(JavassistUtils.forClassPool(pool)); - BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(generator); - GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(); - bindingToNormalized = new BindingToNormalizedNodeCodec(loading, mappingService, codecRegistry); - schemaService.registerSchemaContextListener(bindingToNormalized); + mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault()); } public DOMStore createConfigurationDatastore() { @@ -82,13 +69,14 @@ public class DataBrokerTestCustomizer { } public DataBroker createDataBroker() { - return new ForwardedBindingDataBroker(getDOMDataBroker(), bindingToNormalized, schemaService ); + return new ForwardedBindingDataBroker(getDOMDataBroker(), getMappingService(), getSchemaService()); } public ForwardedBackwardsCompatibleDataBroker createBackwardsCompatibleDataBroker() { - return new ForwardedBackwardsCompatibleDataBroker(getDOMDataBroker(), bindingToNormalized, getSchemaService(), MoreExecutors.sameThreadExecutor()); + return new ForwardedBackwardsCompatibleDataBroker(getDOMDataBroker(), getMappingService(), getSchemaService(), MoreExecutors.sameThreadExecutor()); } + private SchemaService getSchemaService() { return schemaService; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/compat/MultipleAugmentationPutsTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/compat/MultipleAugmentationPutsTest.java index 63e0e2290a..7b67d3b10f 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/compat/MultipleAugmentationPutsTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/compat/MultipleAugmentationPutsTest.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; + import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; @@ -75,7 +76,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem * * @throws Exception */ - @Test() + @Test( timeout = 15000) public void testAugmentSerialization() throws Exception { baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this); @@ -121,7 +122,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem testNodeRemove(); } - private > Node createTestNode(final Class augmentationClass, final T augmentation) { + private > Node createTestNode(Class augmentationClass, T augmentation) { NodeBuilder nodeBuilder = new NodeBuilder(); nodeBuilder.setId(new NodeId(NODE_ID)); nodeBuilder.setKey(NODE_KEY); @@ -129,7 +130,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem return nodeBuilder.build(); } - private DataModificationTransaction commitNodeAndVerifyTransaction(final Node original) throws Exception { + private DataModificationTransaction commitNodeAndVerifyTransaction(Node original) throws Exception { DataModificationTransaction transaction = baDataService.beginTransaction(); transaction.putOperationalData(NODE_INSTANCE_ID_BA, original); RpcResult result = transaction.commit().get(); @@ -147,7 +148,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem assertNull(node); } - private AugmentationVerifier verifyNode(final Nodes nodes, final Node original) { + private AugmentationVerifier verifyNode(Nodes nodes, Node original) { assertNotNull(nodes); assertNotNull(nodes.getNode()); assertEquals(1, nodes.getNode().size()); @@ -157,7 +158,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem return new AugmentationVerifier(readedNode); } - private void assertBindingIndependentVersion(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier nodeId) { + private void assertBindingIndependentVersion(org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier nodeId) { CompositeNode node = biDataService.readOperationalData(nodeId); assertNotNull(node); } @@ -170,7 +171,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem return nodeMeterStatistics(10, false); } - private NodeMeterStatistics nodeMeterStatistics(final int count, final boolean setDuration) { + private NodeMeterStatistics nodeMeterStatistics(int count, boolean setDuration) { NodeMeterStatisticsBuilder nmsb = new NodeMeterStatisticsBuilder(); MeterStatisticsBuilder meterStats = new MeterStatisticsBuilder(); @@ -206,7 +207,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem } @Override - public void onDataChanged(final DataChangeEvent, DataObject> change) { + public void onDataChanged(DataChangeEvent, DataObject> change) { receivedChangeEvent = change; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java index d0a326adff..fef5715f50 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java @@ -9,19 +9,12 @@ package org.opendaylight.controller.sal.binding.test.util; import static com.google.common.base.Preconditions.checkState; -import com.google.common.annotations.Beta; -import com.google.common.collect.ClassToInstanceMap; -import com.google.common.collect.ImmutableClassToInstanceMap; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.MutableClassToInstanceMap; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; import java.util.Set; import java.util.concurrent.Future; + import javassist.ClassPool; + import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; import org.opendaylight.controller.md.sal.binding.impl.ForwardedBackwardsCompatibleDataBroker; import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; @@ -50,14 +43,9 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStore; import org.opendaylight.controller.sal.dom.broker.BrokerImpl; import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl; import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker; -import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator; -import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; -import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy; import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl; -import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; import org.opendaylight.yangtools.yang.binding.YangModuleInfo; import org.opendaylight.yangtools.yang.binding.util.BindingReflections; import org.opendaylight.yangtools.yang.common.QName; @@ -68,6 +56,15 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.annotations.Beta; +import com.google.common.collect.ClassToInstanceMap; +import com.google.common.collect.ImmutableClassToInstanceMap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.MutableClassToInstanceMap; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + @Beta public class BindingTestContext implements AutoCloseable { @@ -77,7 +74,6 @@ public class BindingTestContext implements AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(BindingTestContext.class); private RuntimeGeneratedMappingServiceImpl mappingServiceImpl; - private BindingToNormalizedNodeCodec codec; private DomForwardedBindingBrokerImpl baBrokerImpl; private DataBrokerImpl baDataImpl; @@ -133,7 +129,7 @@ public class BindingTestContext implements AutoCloseable { public void startNewDataBroker() { checkState(executor != null, "Executor needs to be set"); checkState(newDOMDataBroker != null, "DOM Data Broker must be set"); - dataBroker = new ForwardedBindingDataBroker(newDOMDataBroker, codec, mockSchemaService); + dataBroker = new ForwardedBindingDataBroker(newDOMDataBroker, mappingServiceImpl, mockSchemaService); } public void startNewDomDataBroker() { @@ -254,12 +250,6 @@ public class BindingTestContext implements AutoCloseable { checkState(classPool != null, "ClassPool needs to be present"); mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl(classPool); mockSchemaService.registerSchemaContextListener(mappingServiceImpl); - - DataObjectSerializerGenerator generator = StreamWriterGenerator.create(JavassistUtils.forClassPool(classPool)); - BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(generator); - GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(); - codec = new BindingToNormalizedNodeCodec(loading, mappingServiceImpl, codecRegistry); - mockSchemaService.registerSchemaContextListener(codec); } private void updateYangSchema(final ImmutableSet moduleInfos) { @@ -290,7 +280,7 @@ public class BindingTestContext implements AutoCloseable { } public void startNewBindingDataBroker() { - ForwardedBackwardsCompatibleDataBroker forwarded = new ForwardedBackwardsCompatibleDataBroker(newDOMDataBroker, codec,mockSchemaService, executor); + ForwardedBackwardsCompatibleDataBroker forwarded = new ForwardedBackwardsCompatibleDataBroker(newDOMDataBroker, mappingServiceImpl,mockSchemaService, executor); baData = forwarded; } diff --git a/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java b/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java index 344694381a..83a69969b7 100644 --- a/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java +++ b/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java @@ -112,7 +112,6 @@ public class TestHelper { mavenBundle(YANGTOOLS, "binding-generator-api").versionAsInProject(), mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(), // mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(), - mavenBundle(YANGTOOLS, "binding-data-codec").versionAsInProject(), mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), // // mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), // diff --git a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/DataServiceTest.java b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/DataServiceTest.java index 33039ea231..8a390b337e 100644 --- a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/DataServiceTest.java +++ b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/DataServiceTest.java @@ -11,10 +11,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import com.google.inject.Inject; import java.util.concurrent.Future; + import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; @@ -23,6 +22,7 @@ import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; 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.inventory.rev130819.nodes.NodeBuilder; @@ -31,6 +31,8 @@ import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; +import com.google.inject.Inject; + public class DataServiceTest extends AbstractTest { protected DataBrokerService consumerDataService; @@ -43,20 +45,12 @@ public class DataServiceTest extends AbstractTest { public void setUp() throws Exception { } - /* - * - * Ignored this, because classes here are constructed from - * very different class loader as MD-SAL is run into, - * this is code is run from different classloader. - * - */ @Test - @Ignore public void test() throws Exception { BindingAwareConsumer consumer1 = new BindingAwareConsumer() { @Override - public void onSessionInitialized(final ConsumerContext session) { + public void onSessionInitialized(ConsumerContext session) { consumerDataService = session.getSALService(DataBrokerService.class); } }; @@ -68,12 +62,12 @@ public class DataServiceTest extends AbstractTest { DataModificationTransaction transaction = consumerDataService.beginTransaction(); assertNotNull(transaction); - InstanceIdentifier node1 = createNodeRef("0"); - DataObject node = consumerDataService.readConfigurationData(node1); + NodeRef node1 = createNodeRef("0"); + DataObject node = consumerDataService.readConfigurationData(node1.getValue()); assertNull(node); Node nodeData1 = createNode("0"); - transaction.putConfigurationData(node1, nodeData1); + transaction.putConfigurationData(node1.getValue(), nodeData1); Future> commitResult = transaction.commit(); assertNotNull(commitResult); @@ -83,7 +77,7 @@ public class DataServiceTest extends AbstractTest { assertNotNull(result.getResult()); assertEquals(TransactionStatus.COMMITED, result.getResult()); - Node readedData = (Node) consumerDataService.readConfigurationData(node1); + Node readedData = (Node) consumerDataService.readConfigurationData(node1.getValue()); assertNotNull(readedData); assertEquals(nodeData1.getKey(), readedData.getKey()); @@ -91,7 +85,7 @@ public class DataServiceTest extends AbstractTest { DataModificationTransaction transaction2 = consumerDataService.beginTransaction(); assertNotNull(transaction); - transaction2.removeConfigurationData(node1); + transaction2.removeConfigurationData(node1.getValue()); Future> commitResult2 = transaction2.commit(); assertNotNull(commitResult2); @@ -102,19 +96,21 @@ public class DataServiceTest extends AbstractTest { assertNotNull(result2.getResult()); assertEquals(TransactionStatus.COMMITED, result2.getResult()); - DataObject readedData2 = consumerDataService.readConfigurationData(node1); + DataObject readedData2 = consumerDataService.readConfigurationData(node1.getValue()); assertNull(readedData2); } - private static InstanceIdentifier createNodeRef(final String string) { + private static NodeRef createNodeRef(String string) { NodeKey key = new NodeKey(new NodeId(string)); - return InstanceIdentifier.builder(Nodes.class).child(Node.class, key).build(); + InstanceIdentifier path = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).build(); + + return new NodeRef(path); } - private static Node createNode(final String string) { + private static Node createNode(String string) { NodeBuilder ret = new NodeBuilder(); NodeId id = new NodeId(string); ret.setKey(new NodeKey(id)); diff --git a/opendaylight/md-sal/sal-binding-it/src/test/resources/controller.xml b/opendaylight/md-sal/sal-binding-it/src/test/resources/controller.xml index 5e37f36a2c..63a921d6f3 100644 --- a/opendaylight/md-sal/sal-binding-it/src/test/resources/controller.xml +++ b/opendaylight/md-sal/sal-binding-it/src/test/resources/controller.xml @@ -38,104 +38,124 @@ - prefix:schema-service-singleton + + prefix:schema-service-singleton + yang-schema-service - prefix:runtime-generated-mapping - runtime-mapping-singleton + + prefix:hash-map-data-store + + hash-map-data-store - prefix:binding-notification-broker - binding-notification-broker + + prefix:dom-broker-impl + + dom-broker + + + dom:dom-data-store + + ref_hash-map-data-store + - prefix:binding-broker-impl + + prefix:binding-broker-impl + binding-broker-impl - - binding:binding-notification-service - binding-notification-broker + + + binding:binding-notification-service + + ref_binding-notification-broker - binding:binding-data-broker - binding-data-broker + + binding:binding-data-broker + + ref_binding-data-broker - - - prefix:dom-inmemory-data-broker - inmemory-data-broker - - dom:schema-service - yang-schema-service - - - prefix:dom-broker-impl - inmemory-dom-broker - - dom:dom-async-data-broker - inmemory-data-broker - + + prefix:runtime-generated-mapping + + runtime-mapping-singleton - prefix:binding-data-compatible-broker - inmemory-binding-data-broker - - dom:dom-broker-osgi-registry - dom-broker - - - binding:binding-dom-mapping-service - runtime-mapping-singleton - + + prefix:binding-notification-broker + + binding-notification-broker - prefix:binding-forwarded-data-broker - binding-async-data-broker - - - dom:dom-broker-osgi-registry - dom-broker - - - binding:binding-dom-mapping-service - runtime-mapping-singleton - - + + prefix:binding-data-broker + + binding-data-broker + + + dom:dom-broker-osgi-registry + + ref_dom-broker + + + + binding:binding-dom-mapping-service + + ref_runtime-mapping-singleton + - dom:schema-service + + dom:schema-service + - yang-schema-service - /modules/module[type='schema-service-singleton'][name='yang-schema-service'] + ref_yang-schema-service + + /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service'] + - binding-impl:binding-dom-mapping-service + + binding:binding-notification-service + - runtime-mapping-singleton - /modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton'] + ref_binding-notification-broker + + /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker'] + - binding:binding-notification-service + + dom:dom-data-store + - binding-notification-broker - /modules/module[type='binding-notification-broker'][name='binding-notification-broker'] + ref_hash-map-data-store + + /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store'] + + - binding:binding-broker-osgi-registry + + binding:binding-broker-osgi-registry + - binding-osgi-broker - /modules/module[type='binding-broker-impl'][name='binding-broker-impl'] + ref_binding-broker-impl + + /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl'] + @@ -145,36 +165,36 @@ /modules/module[type='binding-broker-impl'][name='binding-broker-impl'] - - - dom:dom-broker-osgi-registry - - dom-broker - /modules/module[type='dom-broker-impl'][name='inmemory-dom-broker'] - - - - binding:binding-data-broker + + binding-impl:binding-dom-mapping-service + - binding-data-broker - /modules/module[type='binding-data-compatible-broker'][name='inmemory-binding-data-broker'] + ref_runtime-mapping-singleton + + /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton'] + - - binding:binding-async-data-broker + + dom:dom-broker-osgi-registry + - binding-data-broker - /modules/module[type='binding-forwarded-data-broker'][name='binding-async-data-broker'] + ref_dom-broker + /config/modules/module[name='dom-broker-impl']/instance[name='dom-broker'] + - - dom:dom-async-data-broker + + binding:binding-data-broker + - inmemory-data-broker - /modules/module[type='dom-inmemory-data-broker'][name='inmemory-data-broker'] + ref_binding-data-broker + + /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker'] + 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-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/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 459eb78903..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 @@ -18,12 +18,12 @@ odl-cluster{ log-remote-lifecycle-events = off netty.tcp { hostname = "127.0.0.1" - port = 2551 + port = 2550 } } cluster { - seed-nodes = ["akka.tcp://opendaylight-rpc@127.0.0.1:2551"] + seed-nodes = ["akka.tcp://opendaylight-rpc@127.0.0.1:2550"] 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 b8c0270a61..2747b9e264 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/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 1a14de6f5d..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,6 +35,7 @@ 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; @@ -36,12 +43,16 @@ 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; @@ -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; - } - } - } - - 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; - } - } + .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); } - 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/FlowCapableTopologyProvider.java b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyProvider.java index 0a3b9f6a6b..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 @@ -8,6 +8,7 @@ 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; @@ -44,16 +45,15 @@ public class FlowCapableTopologyProvider extends AbstractBindingAwareProvider im 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(dataBroker); final FlowCapableTopologyExporter listener = new FlowCapableTopologyExporter(processor, path); this.listenerRegistration = notificationService.registerNotificationListener(listener); final ReadWriteTransaction tx = dataBroker.newReadWriteTransaction(); - tx.put(LogicalDatastoreType.OPERATIONAL, path, new TopologyBuilder().setKey(key).build()); + tx.put(LogicalDatastoreType.OPERATIONAL, path, new TopologyBuilder().setKey(key).build(), true); try { tx.submit().get(); } catch (InterruptedException | ExecutionException e) {