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";
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 {
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 + ":"
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 + "="
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 + ","
--- /dev/null
+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
--- /dev/null
+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<String, Map<String, ValidationException.ExceptionMessageWithStackTrace>> failedMap = collected.getFailedValidations();
+ assertEquals(1, failedMap.size());
+ assertTrue(failedMap.containsKey("module"));
+
+ Map<String, ValidationException.ExceptionMessageWithStackTrace> 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
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.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<String, String> 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<? extends Exception> 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);
+ }
+}
*/
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;
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)}
public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer<ModuleFactory, Object> {
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
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) {
public void removedService(ServiceReference<ModuleFactory> moduleFactoryServiceReference, Object o) {
blankTransaction();
}
+
+ @VisibleForTesting
+ static interface BlankTransaction {
+ CommitStatus hit() throws ValidationException, ConflictingVersionException;
+ }
}
import static java.lang.String.format;
+import com.google.common.annotations.VisibleForTesting;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
blankTransactionServiceTracker.blankTransaction();
}
- // TODO:test
- private static ServiceRegistration<?> 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)) {
errorMessage = logMessage(
"Could not instantiate {} in bundle {}, reason {}",
factoryClassName, bundle, e);
+ ex = e;
} catch (IllegalAccessException e) {
errorMessage = logMessage(
- "Illegal access during instatiation of class {} in bundle {}, reason {}",
+ "Illegal access during instantiation of class {} in bundle {}, reason {}",
factoryClassName, bundle, e);
+ ex = e;
}
} else {
errorMessage = logMessage(
}
} catch (ClassNotFoundException e) {
errorMessage = logMessage(
- "Could not find class {} in bunde {}, reason {}",
+ "Could not find class {} in bundle {}, reason {}",
factoryClassName, bundle, e);
+ ex = e;
}
- throw new IllegalStateException(errorMessage);
+
+ throw ex == null ? new IllegalStateException(errorMessage) : new IllegalStateException(errorMessage, ex);
}
public static String logMessage(String slfMessage, Object... params) {
*/
public static Set<Class<?>> getOsgiRegistrationTypes(
Class<? extends Module> configBeanClass) {
- // TODO test with service interface hierarchy
Set<Class<?>> serviceInterfaces = getServiceInterfaces(configBeanClass);
Set<Class<?>> result = new HashSet<>();
for (Class<?> clazz : serviceInterfaces) {
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;
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;
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;
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);
--- /dev/null
+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.<ObjectName>emptyList(), Collections.<ObjectName>emptyList(), Collections.<ObjectName>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<ModuleFactory> getMockServiceReference() {
+ return mock(ServiceReference.class);
+ }
+}
--- /dev/null
+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<String, Map.Entry<ModuleFactory, BundleContext>> 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();
+ }
+}
--- /dev/null
+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<Object> primaryTracker;
+ @Mock
+ private BundleTrackerCustomizer<?> additionalTracker;
+
+ private ExtensibleBundleTracker<Object> 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);
+ }
+}
--- /dev/null
+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<? extends AbstractServiceInterface> serviceInterface) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<? extends Module> getDefaultModules(final DependencyResolverFactory dependencyResolverFactory, final BundleContext bundleContext) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
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 {
}
+ @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<Class<?>> expected = Sets.<Class<?>> newHashSet(SuperA.class, SuperBMXBean.class, SuperC.class,
InterfacesHelper.getAllInterfaces(SubClass.class));
}
+ @Test
+ public void testGetServiceInterfaces() throws Exception {
+ assertEquals(Collections.<Class<?>>emptySet(), InterfacesHelper.getServiceInterfaces(SubClass.class));
+ assertEquals(Sets.<Class<?>>newHashSet(Service.class, SubService.class), InterfacesHelper.getServiceInterfaces(SubClassWithService.class));
+ }
+
+ @Test
+ public void testGetOsgiRegistrationTypes() throws Exception {
+ assertEquals(Collections.<Class<?>>emptySet(), InterfacesHelper.getOsgiRegistrationTypes(SubClass.class));
+ assertEquals(Sets.<Class<?>>newHashSet(SuperA.class, SuperC.class),
+ InterfacesHelper.getOsgiRegistrationTypes(SubClassWithService.class));
+ }
+
@Test
public void testGetMXInterfaces() {
Set<Class<?>> expected = Sets.<Class<?>> newHashSet(SuperBMXBean.class, SubA.class);
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.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<ObjectName> 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));
-
- }
-}
--- /dev/null
+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
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 {
}
@Test
public void testQNames() {
Set<String> availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames();
- String expected = "(namespace?revision=revision)name";
+ String expected = "(namespace?revision=2012-12-12)name";
+
assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames);
}
--- /dev/null
+org.opendaylight.controller.config.manager.impl.osgi.ModuleFactoryBundleTrackerTest$NotExtendingTestingFactory
\ No newline at end of file
--- /dev/null
+org.opendaylight.controller.config.manager.impl.osgi.ModuleFactoryBundleTrackerTest$TestingFactory
\ No newline at end of file
<groupId>${project.groupId}</groupId>
<artifactId>netconf-client</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-manager</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-manager</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-util</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netty-threadgroup-config</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netty-timer-config</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
--- /dev/null
+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;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.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;
+ }
+
+}
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 {
*/
package org.opendaylight.controller.md.inventory.manager;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.LinkedBlockingDeque;
-
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Preconditions;
-
class FlowCapableInventoryProvider implements AutoCloseable, Runnable {
private static final Logger LOG = LoggerFactory.getLogger(FlowCapableInventoryProvider.class);
private static final int QUEUE_DEPTH = 500;
private final BlockingQueue<InventoryOperation> queue = new LinkedBlockingDeque<>(QUEUE_DEPTH);
private final NotificationProviderService notificationService;
- private final DataProviderService dataService;
+
+ private final DataBroker dataBroker;
private ListenerRegistration<?> listenerRegistration;
private Thread thread;
- FlowCapableInventoryProvider(final DataProviderService dataService, final NotificationProviderService notificationService) {
- this.dataService = Preconditions.checkNotNull(dataService);
+ FlowCapableInventoryProvider(final DataBroker dataBroker, final NotificationProviderService notificationService) {
+ this.dataBroker = Preconditions.checkNotNull(dataBroker);
this.notificationService = Preconditions.checkNotNull(notificationService);
}
@Override
public void run() {
try {
- for (;;) {
+ for (; ; ) {
InventoryOperation op = queue.take();
- final DataModificationTransaction tx = dataService.beginTransaction();
+ final ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
LOG.debug("New operations available, starting transaction {}", tx.getIdentifier());
int ops = 0;
LOG.debug("Processed {} operations, submitting transaction {}", ops, tx.getIdentifier());
- try {
- final RpcResult<TransactionStatus> result = tx.commit().get();
- if(!result.isSuccessful()) {
- LOG.error("Transaction {} failed", tx.getIdentifier());
+ final CheckedFuture<Void, TransactionCommitFailedException> result = tx.submit();
+ Futures.addCallback(result, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void aVoid) {
+ //NOOP
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ LOG.error("Transaction {} failed.", tx.getIdentifier(), throwable);
}
- } catch (ExecutionException e) {
- LOG.warn("Failed to commit inventory change", e.getCause());
- }
+ });
}
} catch (InterruptedException e) {
LOG.info("Processing interrupted, terminating", e);
*/
package org.opendaylight.controller.md.inventory.manager;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Override
public void onSessionInitiated(final ProviderContext session) {
- DataProviderService salDataService = session.getSALService(DataProviderService.class);
+ DataBroker dataBroker = session.getSALService(DataBroker.class);
NotificationProviderService salNotifiService =
session.getSALService(NotificationProviderService.class);
- provider = new FlowCapableInventoryProvider(salDataService, salNotifiService);
+ provider = new FlowCapableInventoryProvider(dataBroker, salNotifiService);
provider.start();
}
*/
package org.opendaylight.controller.md.inventory.manager;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
interface InventoryOperation {
- void applyOperation(DataModificationTransaction tx);
+ void applyOperation(ReadWriteTransaction tx);
}
*/
package org.opendaylight.controller.md.inventory.manager;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Preconditions;
-
class NodeChangeCommiter implements OpendaylightInventoryListener {
private static final Logger LOG = LoggerFactory.getLogger(NodeChangeCommiter.class);
@Override
public synchronized void onNodeConnectorRemoved(final NodeConnectorRemoved connector) {
+ LOG.debug("Node connector removed notification received.");
manager.enqueue(new InventoryOperation() {
@Override
- public void applyOperation(final DataModificationTransaction tx) {
+ public void applyOperation(final ReadWriteTransaction tx) {
final NodeConnectorRef ref = connector.getNodeConnectorRef();
LOG.debug("removing node connector {} ", ref.getValue());
- tx.removeOperationalData(ref.getValue());
+ tx.delete(LogicalDatastoreType.OPERATIONAL, ref.getValue());
}
});
}
@Override
public synchronized void onNodeConnectorUpdated(final NodeConnectorUpdated connector) {
+ LOG.debug("Node connector updated notification received.");
manager.enqueue(new InventoryOperation() {
@Override
- public void applyOperation(final DataModificationTransaction tx) {
+ public void applyOperation(final ReadWriteTransaction tx) {
final NodeConnectorRef ref = connector.getNodeConnectorRef();
final NodeConnectorBuilder data = new NodeConnectorBuilder(connector);
data.setKey(new NodeConnectorKey(connector.getId()));
final FlowCapableNodeConnector augment = InventoryMapping.toInventoryAugment(flowConnector);
data.addAugmentation(FlowCapableNodeConnector.class, augment);
}
- InstanceIdentifier<? extends Object> value = ref.getValue();
+ InstanceIdentifier<NodeConnector> value = (InstanceIdentifier<NodeConnector>) ref.getValue();
LOG.debug("updating node connector : {}.", value);
NodeConnector build = data.build();
- tx.putOperationalData(value, build);
+ tx.put(LogicalDatastoreType.OPERATIONAL, value, build);
}
});
}
@Override
public synchronized void onNodeRemoved(final NodeRemoved node) {
+ LOG.debug("Node removed notification received.");
manager.enqueue(new InventoryOperation() {
@Override
- public void applyOperation(final DataModificationTransaction tx) {
+ public void applyOperation(final ReadWriteTransaction tx) {
final NodeRef ref = node.getNodeRef();
LOG.debug("removing node : {}", ref.getValue());
- tx.removeOperationalData((ref.getValue()));
+ tx.delete(LogicalDatastoreType.OPERATIONAL, ref.getValue());
}
});
}
if (flowNode == null) {
return;
}
-
+ LOG.debug("Node updated notification received.");
manager.enqueue(new InventoryOperation() {
@Override
- public void applyOperation(final DataModificationTransaction tx) {
+ public void applyOperation(ReadWriteTransaction tx) {
final NodeRef ref = node.getNodeRef();
+ @SuppressWarnings("unchecked")
+ InstanceIdentifierBuilder<Node> builder = ((InstanceIdentifier<Node>) ref.getValue()).builder();
+ InstanceIdentifierBuilder<FlowCapableNode> augmentation = builder.augmentation(FlowCapableNode.class);
+ final InstanceIdentifier<FlowCapableNode> path = augmentation.build();
+ CheckedFuture readFuture = tx.read(LogicalDatastoreType.OPERATIONAL, path);
+ Futures.addCallback(readFuture, new FutureCallback<Optional<? extends DataObject>>() {
+ @Override
+ public void onSuccess(Optional<? extends DataObject> 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<FlowCapableNode> 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<Node> builder = ((InstanceIdentifier<Node>) ref.getValue()).builder();
- InstanceIdentifierBuilder<FlowCapableNode> augmentation = builder.augmentation(FlowCapableNode.class);
- final InstanceIdentifier<FlowCapableNode> path = augmentation.build();
LOG.debug("updating node :{} ", path);
- tx.putOperationalData(path, augment);
+ tx.put(LogicalDatastoreType.OPERATIONAL, path, augment);
+ }
+ });
+ }
+
+ private void enqueuePutTable0Tx(final NodeRef ref) {
+ manager.enqueue(new InventoryOperation() {
+ @Override
+ public void applyOperation(ReadWriteTransaction tx) {
+ final TableKey tKey = new TableKey((short) 0);
+ final InstanceIdentifier<Table> tableIdentifier =
+ ((InstanceIdentifier<Node>) 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);
}
});
}
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: CompositeModificationPayload.proto
-package org.opendaylight.controller.mdsal;
+package org.opendaylight.controller.protobuff.messages.shard;
public final class CompositeModificationPayload {
private CompositeModificationPayload() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
- registry.add(org.opendaylight.controller.mdsal.CompositeModificationPayload.modification);
+ registry.add(org.opendaylight.controller.protobuff.messages.shard.CompositeModificationPayload.modification);
}
public static final int MODIFICATION_FIELD_NUMBER = 2;
/**
"daylight.controller.cluster.raft.AppendE" +
"ntries.ReplicatedLogEntry.Payload\030\002 \001(\0132" +
"8.org.opendaylight.controller.mdsal.Comp" +
- "ositeModification"
+ "ositeModificationB6\n4org.opendaylight.co" +
+ "ntroller.protobuff.messages.shard"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
import "Common.proto";
import "Persistent.proto";
+option java_package = "org.opendaylight.controller.protobuff.messages.shard";
+
extend org.opendaylight.controller.cluster.raft.AppendEntries.ReplicatedLogEntry.Payload {
optional CompositeModification modification=2;
}
<description>Configuration files for md-sal clustering</description>
<packaging>jar</packaging>
<build>
- <plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>attach-artifacts</id>
- <goals>
- <goal>attach-artifact</goal>
- </goals>
- <phase>package</phase>
- <configuration>
- <artifacts>
- <artifact>
- <file>${project.build.directory}/classes/initial/*.conf</file>
- <type>xml</type>
- <classifier>config</classifier>
- </artifact>
- </artifacts>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
</build>
</project>
@Override public Map<GeneratedMessage.GeneratedExtension, PersistentMessages.CompositeModification> encode() {
Preconditions.checkState(modification!=null);
Map<GeneratedMessage.GeneratedExtension, PersistentMessages.CompositeModification> map = new HashMap<>();
- map.put(org.opendaylight.controller.mdsal.CompositeModificationPayload.modification, this.modification);
+ map.put(
+ org.opendaylight.controller.protobuff.messages.shard.CompositeModificationPayload.modification, this.modification);
return map;
}
AppendEntriesMessages.AppendEntries.ReplicatedLogEntry.Payload payload) {
PersistentMessages.CompositeModification modification = payload
.getExtension(
- org.opendaylight.controller.mdsal.CompositeModificationPayload.modification);
+ org.opendaylight.controller.protobuff.messages.shard.CompositeModificationPayload.modification);
log-remote-lifecycle-events = off
netty.tcp {
- hostname = "localhost"
+ hostname = "127.0.0.1"
port = 2551
}
}
cluster {
- seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"]
+ seed-nodes = ["akka.tcp://opendaylight-rpc@127.0.0.1:2551"]
auto-down-unreachable-after = 10s
}
log-remote-lifecycle-events = off
netty.tcp {
- hostname = "localhost"
+ hostname = "127.0.0.1"
port = 2551
}
}
cluster {
- seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"]
+ seed-nodes = ["akka.tcp://opendaylight-rpc@127.0.0.1:2551"]
auto-down-unreachable-after = 10s
}
log-remote-lifecycle-events = off
netty.tcp {
- hostname = "localhost"
+ hostname = "127.0.0.1"
port = 2552
}
}
cluster {
- seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"]
+ seed-nodes = ["akka.tcp://opendaylight-rpc@127.0.0.1:2551"]
auto-down-unreachable-after = 10s
}
log-remote-lifecycle-events = off
netty.tcp {
- hostname = "localhost"
+ hostname = "127.0.0.1"
port = 2553
}
}
cluster {
- seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"]
+ seed-nodes = ["akka.tcp://opendaylight-rpc@127.0.0.1:2551"]
auto-down-unreachable-after = 10s
}
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Override
protected void cleanupSingleStat(final DataModificationTransaction trans, final FlowStatsEntry item) {
- InstanceIdentifier<?> flowRef = getNodeIdentifierBuilder()
- .augmentation(FlowCapableNode.class)
- .child(Table.class, new TableKey(item.getTableId()))
- .child(Flow.class,item.getFlow().getKey())
- .augmentation(FlowStatisticsData.class).toInstance();
+ KeyedInstanceIdentifier<Flow, FlowKey> flowRef = getNodeIdentifier()
+ .augmentation(FlowCapableNode.class)
+ .child(Table.class, new TableKey(item.getTableId()))
+ .child(Flow.class, item.getFlow().getKey());
trans.removeOperationalData(flowRef);
}
import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNode;
import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNodeId;
-import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryListener;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-import com.google.common.base.Preconditions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, OpendaylightInventoryListener {
+
+ private final Logger LOG = LoggerFactory.getLogger(FlowCapableTopologyExporter.class);
private final InstanceIdentifier<Topology> topology;
private final OperationProcessor processor;
@Override
public void onNodeRemoved(final NodeRemoved notification) {
+
+ final NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeRef()).getId());
+ final InstanceIdentifier<Node> nodeInstance = toNodeIdentifier(notification.getNodeRef());
+
processor.enqueueOperation(new TopologyOperation() {
@Override
- public void applyOperation(final DataModificationTransaction transaction) {
- NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeRef()).getId());
- InstanceIdentifier<Node> nodeInstance = toNodeIdentifier(notification.getNodeRef());
- transaction.removeOperationalData(nodeInstance);
- removeAffectedLinks(transaction, nodeId);
+ public void applyOperation(final ReadWriteTransaction transaction) {
+ removeAffectedLinks(nodeId);
+ }
+ });
+
+ processor.enqueueOperation(new TopologyOperation() {
+ @Override
+ public void applyOperation(ReadWriteTransaction transaction) {
+ transaction.delete(LogicalDatastoreType.OPERATIONAL, nodeInstance);
}
});
}
if (fcnu != null) {
processor.enqueueOperation(new TopologyOperation() {
@Override
- public void applyOperation(final DataModificationTransaction transaction) {
- Node node = toTopologyNode(toTopologyNodeId(notification.getId()), notification.getNodeRef());
- InstanceIdentifier<Node> path = getNodePath(toTopologyNodeId(notification.getId()));
- transaction.putOperationalData(path, node);
+ public void applyOperation(final ReadWriteTransaction transaction) {
+ final Node node = toTopologyNode(toTopologyNodeId(notification.getId()), notification.getNodeRef());
+ final InstanceIdentifier<Node> path = getNodePath(toTopologyNodeId(notification.getId()));
+ transaction.put(LogicalDatastoreType.OPERATIONAL, path, node);
}
});
}
@Override
public void onNodeConnectorRemoved(final NodeConnectorRemoved notification) {
+
+ final InstanceIdentifier<TerminationPoint> tpInstance = toTerminationPointIdentifier(notification
+ .getNodeConnectorRef());
+
processor.enqueueOperation(new TopologyOperation() {
@Override
- public void applyOperation(final DataModificationTransaction transaction) {
- InstanceIdentifier<TerminationPoint> tpInstance = toTerminationPointIdentifier(notification
- .getNodeConnectorRef());
- TpId tpId = toTerminationPointId(getNodeConnectorKey(notification.getNodeConnectorRef()).getId());
+ public void applyOperation(final ReadWriteTransaction transaction) {
+ final TpId tpId = toTerminationPointId(getNodeConnectorKey(notification.getNodeConnectorRef()).getId());
+ removeAffectedLinks(tpId);
+ }
+ });
- transaction.removeOperationalData(tpInstance);
- removeAffectedLinks(transaction, tpId);
+ processor.enqueueOperation(new TopologyOperation() {
+ @Override
+ public void applyOperation(ReadWriteTransaction transaction) {
+ transaction.delete(LogicalDatastoreType.OPERATIONAL, tpInstance);
}
});
}
if (fcncu != null) {
processor.enqueueOperation(new TopologyOperation() {
@Override
- public void applyOperation(final DataModificationTransaction transaction) {
- NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeConnectorRef()).getId());
+ public void applyOperation(final ReadWriteTransaction transaction) {
+ final NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeConnectorRef()).getId());
TerminationPoint point = toTerminationPoint(toTerminationPointId(notification.getId()),
notification.getNodeConnectorRef());
- InstanceIdentifier<TerminationPoint> path = tpPath(nodeId, point.getKey().getTpId());
-
- transaction.putOperationalData(path, point);
+ final InstanceIdentifier<TerminationPoint> path = tpPath(nodeId, point.getKey().getTpId());
+ transaction.put(LogicalDatastoreType.OPERATIONAL, path, point);
if ((fcncu.getState() != null && fcncu.getState().isLinkDown())
|| (fcncu.getConfiguration() != null && fcncu.getConfiguration().isPORTDOWN())) {
- removeAffectedLinks(transaction, point.getTpId());
+ removeAffectedLinks(point.getTpId());
}
}
});
public void onLinkDiscovered(final LinkDiscovered notification) {
processor.enqueueOperation(new TopologyOperation() {
@Override
- public void applyOperation(final DataModificationTransaction transaction) {
- Link link = toTopologyLink(notification);
- InstanceIdentifier<Link> path = linkPath(link);
- transaction.putOperationalData(path, link);
+ public void applyOperation(final ReadWriteTransaction transaction) {
+ final Link link = toTopologyLink(notification);
+ final InstanceIdentifier<Link> path = linkPath(link);
+ transaction.put(LogicalDatastoreType.OPERATIONAL, path, link);
}
});
}
public void onLinkRemoved(final LinkRemoved notification) {
processor.enqueueOperation(new TopologyOperation() {
@Override
- public void applyOperation(final DataModificationTransaction transaction) {
- transaction.removeOperationalData(linkPath(toTopologyLink(notification)));
+ public void applyOperation(final ReadWriteTransaction transaction) {
+ transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(toTopologyLink(notification)));
}
});
}
return tpPath(toTopologyNodeId(invNodeKey.getId()), toTerminationPointId(invNodeConnectorKey.getId()));
}
- private void removeAffectedLinks(final DataModificationTransaction transaction, final NodeId id) {
- TypeSafeDataReader reader = TypeSafeDataReader.forReader(transaction);
- Topology topologyData = reader.readOperationalData(topology);
- if (topologyData != null) {
- for (Link link : topologyData.getLink()) {
- if (id.equals(link.getSource().getSourceNode()) || id.equals(link.getDestination().getDestNode())) {
- transaction.removeOperationalData(linkPath(link));
- }
+ private void removeAffectedLinks(final NodeId id) {
+ processor.enqueueOperation(new TopologyOperation() {
+ @Override
+ public void applyOperation(final ReadWriteTransaction transaction) {
+ CheckedFuture<Optional<Topology>, ReadFailedException> topologyDataFuture = transaction.read(LogicalDatastoreType.OPERATIONAL, topology);
+ Futures.addCallback(topologyDataFuture, new FutureCallback<Optional<Topology>>() {
+ @Override
+ public void onSuccess(Optional<Topology> topologyOptional) {
+ if (topologyOptional.isPresent()) {
+ Topology topologyData = topologyOptional.get();
+ for (Link link : topologyData.getLink()) {
+ if (id.equals(link.getSource().getSourceNode()) || id.equals(link.getDestination().getDestNode())) {
+ transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(link));
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ LOG.error("Error reading topology data for topology {}", topology, throwable);
+ }
+ });
}
- }
+ });
}
- private void removeAffectedLinks(final DataModificationTransaction transaction, final TpId id) {
- TypeSafeDataReader reader = TypeSafeDataReader.forReader(transaction);
- Topology topologyData = reader.readOperationalData(topology);
- if (topologyData != null) {
- for (Link link : topologyData.getLink()) {
- if (id.equals(link.getSource().getSourceTp()) || id.equals(link.getDestination().getDestTp())) {
- transaction.removeOperationalData(linkPath(link));
- }
+ private void removeAffectedLinks(final TpId id) {
+ processor.enqueueOperation(new TopologyOperation() {
+ @Override
+ public void applyOperation(final ReadWriteTransaction transaction) {
+ CheckedFuture<Optional<Topology>, ReadFailedException> topologyDataFuture = transaction.read(LogicalDatastoreType.OPERATIONAL, topology);
+ Futures.addCallback(topologyDataFuture, new FutureCallback<Optional<Topology>>() {
+ @Override
+ public void onSuccess(Optional<Topology> topologyOptional) {
+ if (topologyOptional.isPresent()) {
+ Topology topologyData = topologyOptional.get();
+ for (Link link : topologyData.getLink()) {
+ if (id.equals(link.getSource().getSourceTp()) || id.equals(link.getDestination().getDestTp())) {
+ transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(link));
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ LOG.error("Error reading topology data for topology {}", topology, throwable);
+ }
+ });
}
- }
+ });
}
private InstanceIdentifier<Node> getNodePath(final NodeId nodeId) {
package org.opendaylight.md.controller.topology.manager;
import java.util.concurrent.ExecutionException;
-
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
*/
@Override
public synchronized void onSessionInitiated(final ProviderContext session) {
- final DataProviderService dataService = session.getSALService(DataProviderService.class);
+ final DataBroker dataBroker = session.getSALService(DataBroker.class);
final NotificationProviderService notificationService = session.getSALService(NotificationProviderService.class);
final String name = "flow:1";
.child(Topology.class, key)
.build();
- final OperationProcessor processor = new OperationProcessor(dataService);
+ final OperationProcessor processor = new OperationProcessor(dataBroker);
final FlowCapableTopologyExporter listener = new FlowCapableTopologyExporter(processor, path);
this.listenerRegistration = notificationService.registerNotificationListener(listener);
- final DataModificationTransaction tx = dataService.beginTransaction();
- tx.putOperationalData(path, new TopologyBuilder().setKey(key).build());
+ final ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
+ tx.put(LogicalDatastoreType.OPERATIONAL, path, new TopologyBuilder().setKey(key).build());
try {
- tx.commit().get();
+ tx.submit().get();
} catch (InterruptedException | ExecutionException e) {
LOG.warn("Initial topology export failed, continuing anyway", e);
}
/**
* Gets called during stop bundle
*
- * @param context
- * The execution context of the bundle being stopped.
+ * @param context The execution context of the bundle being stopped.
*/
@Override
public void stopImpl(final BundleContext context) {
*/
package org.opendaylight.md.controller.topology.manager;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.LinkedBlockingQueue;
-
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
-import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Preconditions;
-
final class OperationProcessor implements Runnable {
private static final Logger LOG = LoggerFactory.getLogger(OperationProcessor.class);
private static final int MAX_TRANSACTION_OPERATIONS = 100;
private static final int OPERATION_QUEUE_DEPTH = 500;
private final BlockingQueue<TopologyOperation> queue = new LinkedBlockingQueue<>(OPERATION_QUEUE_DEPTH);
- // FIXME: Flow capable topology exporter should use transaction chaining API
- private final DataProviderService dataService;
+ private final DataBroker dataBroker;
- OperationProcessor(final DataProviderService dataService) {
- this.dataService = Preconditions.checkNotNull(dataService);
+ OperationProcessor(final DataBroker dataBroker) {
+ this.dataBroker = Preconditions.checkNotNull(dataBroker);
}
void enqueueOperation(final TopologyOperation task) {
@Override
public void run() {
try {
- for (;;) {
+ for (; ; ) {
TopologyOperation op = queue.take();
LOG.debug("New operations available, starting transaction");
- final DataModificationTransaction tx = dataService.beginTransaction();
+ final ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
int ops = 0;
do {
LOG.debug("Processed {} operations, submitting transaction", ops);
- try {
- final RpcResult<TransactionStatus> s = tx.commit().get();
- if (!s.isSuccessful()) {
- LOG.error("Topology export failed for Tx:{}", tx.getIdentifier());
+ final CheckedFuture txResultFuture = tx.submit();
+ Futures.addCallback(txResultFuture, new FutureCallback() {
+ @Override
+ public void onSuccess(Object o) {
+ LOG.debug("Topology export successful for tx :{}", tx.getIdentifier());
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ LOG.error("Topology export transaction {} failed", tx.getIdentifier(), throwable.getCause());
}
- } catch (ExecutionException e) {
- LOG.error("Topology export transaction {} failed", tx.getIdentifier(), e.getCause());
- }
+ });
}
} catch (InterruptedException e) {
LOG.info("Interrupted processing, terminating", e);
*/
package org.opendaylight.md.controller.topology.manager;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
/**
* Internal interface for submitted operations. Implementations of this
*
* @param transaction Datastore transaction
*/
- void applyOperation(DataModificationTransaction transaction);
+ void applyOperation(ReadWriteTransaction transaction);
}
\ No newline at end of file
@XmlElement (name="tenant_id")
String tenantID;
- @XmlElement (name="external_gateway_info")
+ @XmlElement (name="external_gateway_info", nillable=true)
NeutronRouter_NetworkReference externalGatewayInfo;
+ @XmlElement (name="distributed")
+ Boolean distributed;
+
+ @XmlElement (name="gw_port_id", nillable=true)
+ String gatewayPortId;
+
+ @XmlElement (name="routes")
+ List<String> routes;
+
/* Holds a map of OpenStackRouterInterfaces by subnet UUID
* used for internal mapping to DOVE
*/
this.externalGatewayInfo = externalGatewayInfo;
}
+ public Boolean getDistributed() {
+ return distributed;
+ }
+
+ public void setDistributed(Boolean distributed) {
+ this.distributed = distributed;
+ }
+
+ public String getGatewayPortId() {
+ return gatewayPortId;
+ }
+
+ public void setGatewayPortId(String gatewayPortId) {
+ this.gatewayPortId = gatewayPortId;
+ }
+
+ public List<String> getRoutes() {
+ return routes;
+ }
+
+ public void setRoutes(List<String> routes) {
+ this.routes = routes;
+ }
+
/**
* This method copies selected fields from the object and returns them
* as a new object, suitable for marshaling.
* @return an OpenStackRouters object with only the selected fields
* populated
*/
-
public NeutronRouter extractFields(List<String> fields) {
NeutronRouter ans = new NeutronRouter();
Iterator<String> i = fields.iterator();
if (s.equals("external_gateway_info")) {
ans.setExternalGatewayInfo(this.getExternalGatewayInfo());
}
+ if (s.equals("distributed")) {
+ ans.setDistributed(this.getDistributed());
+ }
+ if (s.equals("gw_port_id")) {
+ ans.setGatewayPortId(this.getGatewayPortId());
+ }
+ if (s.equals("routes")){
+ ans.setRoutes(this.getRoutes());
+ }
}
return ans;
}
// if floating IP is specified, make sure it can come from the network
String floatingIP = singleton.getFloatingIPAddress();
if (floatingIP != null) {
- if (externNetwork.getSubnets().size() > 1)
+ if (externNetwork.getSubnets().size() != 1)
throw new BadRequestException("external network doesn't have a subnet");
NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
if (!externSubnet.isValidIP(floatingIP))
if (!input.isSingleton())
throw new BadRequestException("only singleton requests allowed.");
NeutronFloatingIP singleton = input.getSingleton();
- if (singleton.getID() != null)
+ if (singleton.getID() == null)
throw new BadRequestException("singleton UUID doesn't exist.");
NeutronNetwork externNetwork = networkInterface.getNetwork(
// if floating IP is specified, make sure it can come from the network
String floatingIP = singleton.getFloatingIPAddress();
if (floatingIP != null) {
- if (externNetwork.getSubnets().size() > 1)
+ if (externNetwork.getSubnets().size() != 1)
throw new BadRequestException("external network doesn't have a subnet.");
NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
if (!externSubnet.isValidIP(floatingIP))