From: Tony Tkacik
Date: Wed, 26 Feb 2014 13:41:31 +0000 (+0000)
Subject: Merge "Migrate toaster samples to config-subsystem"
X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~376
X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=4467f6e1ac869d390b607db90cd7e540118a4c6e;hp=4e90dc91054540e5a40144c6349d0bc0dcbba91a;p=controller.git
Merge "Migrate toaster samples to config-subsystem"
---
diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml
index 43e254c88d..acda40035f 100644
--- a/opendaylight/commons/opendaylight/pom.xml
+++ b/opendaylight/commons/opendaylight/pom.xml
@@ -84,7 +84,7 @@
0.5.2-SNAPSHOT
0.7.1-SNAPSHOT
0.1.2-SNAPSHOT
- 0.7.1-SNAPSHOT
+ 0.8.1-SNAPSHOT
0.0.3-SNAPSHOT
0.1.2-SNAPSHOT
0.0.3-SNAPSHOT
diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractProtocolSession.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractProtocolSession.java
index e7bd665740..47e96d1ff4 100644
--- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractProtocolSession.java
+++ b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractProtocolSession.java
@@ -40,6 +40,7 @@ public abstract class AbstractProtocolSession extends SimpleChannelInboundHan
}
@Override
+ @SuppressWarnings("unchecked")
protected final void channelRead0(final ChannelHandlerContext ctx, final Object msg) {
LOG.debug("Message was received: {}", msg);
handleMessage((M) msg);
diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractSessionNegotiator.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractSessionNegotiator.java
index d41e8106c5..cbe9235245 100644
--- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractSessionNegotiator.java
+++ b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractSessionNegotiator.java
@@ -85,6 +85,7 @@ public abstract class AbstractSessionNegotiator
* In order to guide dependency resolution, the setter method should be
- * annotated with {@link RequireInterface}.
+ * annotated with {@link org.opendaylight.controller.config.api.annotations.RequireInterface}.
*
*
* Thread safety note: implementations of this interface are not required to be
@@ -43,10 +43,10 @@ public interface Module extends Identifiable{
* Returns 'live' object that was configured using this object. It is
* allowed to call this method only after all ConfigBeans were validated. In
* this method new resources might be opened or old instance might be
- * modified. Note that when obtaining dependent Module using
- * {@link org.opendaylight.controller.config.api.DependencyResolver#validateDependency(Class, javax.management.ObjectName, String)}
- * a proxy will be created that will disallow calling this method before
- * second commit phase begins.
+ * modified. This method must be implemented so that it returns same
+ * result for a single transaction. Since Module is created per transaction
+ * this means that it must be safe to cache result of first call.
+ *
*
* @return closeable instance: After bundle update the factory might be able
* to copy old configuration into new one without being able to cast
diff --git a/opendaylight/config/config-manager/pom.xml b/opendaylight/config/config-manager/pom.xml
index 4857f2a201..7d7d9d697a 100644
--- a/opendaylight/config/config-manager/pom.xml
+++ b/opendaylight/config/config-manager/pom.xml
@@ -68,7 +68,6 @@
com.google.guava
guava
- test
org.opendaylight.yangtools
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/CommitInfo.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/CommitInfo.java
index 9d086295e3..28732d8f68 100644
--- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/CommitInfo.java
+++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/CommitInfo.java
@@ -14,6 +14,8 @@ import java.util.Map;
import javax.annotation.concurrent.Immutable;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
/**
* Structure obtained during first phase commit, contains destroyed modules from
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java
index 8f6a4654b2..dd510a1ed7 100644
--- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java
+++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java
@@ -7,6 +7,7 @@
*/
package org.opendaylight.controller.config.manager.impl;
+import com.google.common.collect.Maps;
import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
@@ -14,6 +15,8 @@ import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver;
@@ -119,13 +122,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
MBeanServer configMBeanServer,
BaseJMXRegistrator baseJMXRegistrator, CodecRegistry codecRegistry) {
this.resolver = resolver;
- beanToOsgiServiceManager = new BeanToOsgiServiceManager();
+ this.beanToOsgiServiceManager = new BeanToOsgiServiceManager();
this.configMBeanServer = configMBeanServer;
this.baseJMXRegistrator = baseJMXRegistrator;
this.codecRegistry = codecRegistry;
- registryMBeanServer = MBeanServerFactory
+ this.registryMBeanServer = MBeanServerFactory
.createMBeanServer("ConfigRegistry" + configMBeanServer.getDefaultDomain());
- transactionsMBeanServer = MBeanServerFactory
+ this.transactionsMBeanServer = MBeanServerFactory
.createMBeanServer("ConfigTransactions" + configMBeanServer.getDefaultDomain());
}
@@ -173,7 +176,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
throw new IllegalStateException(e);
}
transactionController.copyExistingModulesAndProcessFactoryDiff(currentConfig.getEntries(), lastListOfFactories);
- transactionsHolder.add(transactionName, transactionController);
+ transactionsHolder.add(transactionName, transactionController, txLookupRegistry);
return transactionController;
}
@@ -189,12 +192,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
logger.trace("About to commit {}. Current parentVersion: {}, versionCounter {}", transactionName, version, versionCounter);
// find ConfigTransactionController
- Map transactions = transactionsHolder.getCurrentTransactions();
- ConfigTransactionControllerInternal configTransactionController = transactions.get(transactionName);
- if (configTransactionController == null) {
+ Map> transactions = transactionsHolder.getCurrentTransactions();
+ Entry configTransactionControllerEntry = transactions.get(transactionName);
+ if (configTransactionControllerEntry == null) {
throw new IllegalArgumentException(String.format(
"Transaction with name '%s' not found", transactionName));
}
+ ConfigTransactionControllerInternal configTransactionController = configTransactionControllerEntry.getKey();
// check optimistic lock
if (version != configTransactionController.getParentVersion()) {
throw new ConflictingVersionException(
@@ -209,8 +213,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
lastListOfFactories = Collections.unmodifiableList(configTransactionController.getCurrentlyRegisteredFactories());
// non recoverable from here:
try {
- return secondPhaseCommit(
- configTransactionController, commitInfo);
+ return secondPhaseCommit(configTransactionController, commitInfo, configTransactionControllerEntry.getValue());
} catch (Throwable t) { // some libs throw Errors: e.g.
// javax.xml.ws.spi.FactoryFinder$ConfigurationError
isHealthy = false;
@@ -220,13 +223,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
} else if (t instanceof Error) {
throw (Error) t;
} else {
- throw new IllegalStateException(t);
+ throw new RuntimeException(t);
}
}
}
private CommitStatus secondPhaseCommit(ConfigTransactionControllerInternal configTransactionController,
- CommitInfo commitInfo) {
+ CommitInfo commitInfo, ConfigTransactionLookupRegistry txLookupRegistry) {
// close instances which were destroyed by the user, including
// (hopefully) runtime beans
@@ -255,7 +258,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
.getRuntimeBeanRegistrator();
}
// set runtime jmx registrator if required
- Module module = entry.getModule();
+ Module module = entry.getProxiedModule();
if (module instanceof RuntimeBeanRegistratorAwareModule) {
((RuntimeBeanRegistratorAwareModule) module)
.setRuntimeBeanRegistrator(runtimeBeanRegistrator);
@@ -265,8 +268,9 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
}
// can register runtime beans
- List orderedModuleIdentifiers = configTransactionController
- .secondPhaseCommit();
+ List orderedModuleIdentifiers = configTransactionController.secondPhaseCommit();
+ txLookupRegistry.close();
+ configTransactionController.close();
// copy configuration to read only mode
List newInstances = new LinkedList<>();
@@ -283,7 +287,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
throw new NullPointerException("Module not found "
+ moduleIdentifier);
}
- Module module = entry.getModule();
+
ObjectName primaryReadOnlyON = ObjectNameUtil
.createReadOnlyModuleON(moduleIdentifier);
@@ -300,13 +304,14 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
.createModuleJMXRegistrator();
OsgiRegistration osgiRegistration = null;
+ AutoCloseable instance = entry.getProxiedModule().getInstance();
if (entry.hasOldModule()) {
ModuleInternalInfo oldInternalInfo = entry.getOldInternalInfo();
DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo.getReadableModule();
currentConfig.remove(entry.getIdentifier());
// test if old instance == new instance
- if (oldReadableConfigBean.getInstance().equals(module.getInstance())) {
+ if (oldReadableConfigBean.getInstance().equals(instance)) {
// reused old instance:
// wrap in readable dynamic mbean
reusedInstances.add(primaryReadOnlyON);
@@ -328,9 +333,10 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
// wrap in readable dynamic mbean
newInstances.add(primaryReadOnlyON);
}
+ Module realModule = entry.getRealModule();
DynamicReadableWrapper newReadableConfigBean = new DynamicReadableWrapper(
- module, module.getInstance(), moduleIdentifier,
+ realModule, instance, moduleIdentifier,
registryMBeanServer, configMBeanServer);
// register to JMX
@@ -347,7 +353,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
if (moduleFactory != null) {
BundleContext bc = configTransactionController.
getModuleFactoryBundleContext(moduleFactory.getImplementationName());
- osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(),
+ osgiRegistration = beanToOsgiServiceManager.registerToOsgi(realModule.getClass(),
newReadableConfigBean.getInstance(), entry.getIdentifier(), bc);
} else {
throw new NullPointerException(entry.getIdentifier().getFactoryName() + " ModuleFactory not found.");
@@ -362,7 +368,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
runtimeBeanRegistrator, newModuleJMXRegistrator,
orderingIdx, entry.isDefaultBean());
- newConfigEntries.put(module, newInfo);
+ newConfigEntries.put(realModule, newInfo);
orderingIdx++;
}
currentConfig.addAll(newConfigEntries.values());
@@ -371,8 +377,8 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
version = configTransactionController.getVersion();
// switch readable Service Reference Registry
- readableSRRegistry.close();
- readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(
+ this.readableSRRegistry.close();
+ this.readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(
configTransactionController.getWritableRegistry(), this, baseJMXRegistrator);
return new CommitStatus(newInstances, reusedInstances,
@@ -384,12 +390,12 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
*/
@Override
public synchronized List getOpenConfigs() {
- Map transactions = transactionsHolder
+ Map> transactions = transactionsHolder
.getCurrentTransactions();
List result = new ArrayList<>(transactions.size());
- for (ConfigTransactionControllerInternal configTransactionController : transactions
+ for (Entry configTransactionControllerEntry : transactions
.values()) {
- result.add(configTransactionController.getControllerObjectName());
+ result.add(configTransactionControllerEntry.getKey().getControllerObjectName());
}
return result;
}
@@ -403,11 +409,14 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
@Override
public synchronized void close() {
// abort transactions
- Map transactions = transactionsHolder
+ Map> transactions = transactionsHolder
.getCurrentTransactions();
- for (ConfigTransactionControllerInternal configTransactionController : transactions
+ for (Entry configTransactionControllerEntry : transactions
.values()) {
+
+ ConfigTransactionControllerInternal configTransactionController = configTransactionControllerEntry.getKey();
try {
+ configTransactionControllerEntry.getValue().close();
configTransactionController.abortConfig();
} catch (RuntimeException e) {
logger.warn("Ignoring exception while aborting {}",
@@ -652,15 +661,16 @@ class TransactionsHolder {
* every time current transactions are requested.
*/
@GuardedBy("ConfigRegistryImpl.this")
- private final Map transactions = new HashMap<>();
+ private final Map> transactions = new HashMap<>();
/**
* Can only be called from within synchronized method.
*/
public void add(String transactionName,
- ConfigTransactionControllerInternal transactionController) {
+ ConfigTransactionControllerInternal transactionController, ConfigTransactionLookupRegistry txLookupRegistry) {
Object oldValue = transactions.put(transactionName,
- transactionController);
+ Maps.immutableEntry(transactionController, txLookupRegistry));
if (oldValue != null) {
throw new IllegalStateException(
"Error: two transactions with same name");
@@ -674,13 +684,13 @@ class TransactionsHolder {
*
* @return current view on transactions map.
*/
- public Map getCurrentTransactions() {
+ public Map> getCurrentTransactions() {
// first, remove closed transaction
- for (Iterator> it = transactions
+ for (Iterator>> it = transactions
.entrySet().iterator(); it.hasNext(); ) {
- Entry entry = it
+ Entry> entry = it
.next();
- if (entry.getValue().isClosed()) {
+ if (entry.getValue().getKey().isClosed()) {
it.remove();
}
}
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java
index f7afded51f..84f76c9936 100644
--- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java
+++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java
@@ -13,6 +13,7 @@ import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.config.manager.impl.dependencyresolver.DependencyResolverManager;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicWritableWrapper;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean.ReadOnlyAtomicBooleanImpl;
@@ -95,7 +96,8 @@ class ConfigTransactionControllerImpl implements
this.currentlyRegisteredFactories = currentlyRegisteredFactories;
this.factoriesHolder = new HierarchicalConfigMBeanFactoriesHolder(currentlyRegisteredFactories);
this.transactionStatus = new TransactionStatus();
- this.dependencyResolverManager = new DependencyResolverManager(transactionName, transactionStatus, writableSRRegistry, codecRegistry);
+ this.dependencyResolverManager = new DependencyResolverManager(txLookupRegistry.getTransactionIdentifier(),
+ transactionStatus, writableSRRegistry, codecRegistry);
this.transactionsMBeanServer = transactionsMBeanServer;
this.configMBeanServer = configMBeanServer;
this.blankTransaction = blankTransaction;
@@ -231,11 +233,10 @@ class ConfigTransactionControllerImpl implements
// put wrapper to jmx
TransactionModuleJMXRegistration transactionModuleJMXRegistration = getTxModuleJMXRegistrator()
.registerMBean(writableDynamicWrapper, writableON);
- ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
+
+ dependencyResolverManager.put(
moduleIdentifier, module, moduleFactory,
maybeOldConfigBeanInfo, transactionModuleJMXRegistration, isDefaultBean);
-
- dependencyResolverManager.put(moduleInternalTransactionalInfo);
return writableON;
}
@@ -394,8 +395,6 @@ class ConfigTransactionControllerImpl implements
logger.trace("Committed configuration {}", getTransactionIdentifier());
transactionStatus.setCommitted();
- // unregister this and all modules from jmx
- close();
return dependencyResolverManager.getSortedModuleIdentifiers();
}
@@ -413,8 +412,7 @@ class ConfigTransactionControllerImpl implements
}
public void close() {
- //FIXME: should not close object that was retrieved in constructor, a wrapper object should do that perhaps
- txLookupRegistry.close();
+ dependencyResolverManager.close();
}
@Override
@@ -572,6 +570,7 @@ class ConfigTransactionControllerImpl implements
return writableSRRegistry;
}
+ @Override
public TransactionIdentifier getTransactionIdentifier() {
return txLookupRegistry.getTransactionIdentifier();
}
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java
index 82bae44a01..f6164e3256 100644
--- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java
+++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java
@@ -23,7 +23,7 @@ import org.osgi.framework.BundleContext;
* and {@link ConfigRegistryImpl} (consumer).
*/
interface ConfigTransactionControllerInternal extends
- ConfigTransactionControllerImplMXBean {
+ ConfigTransactionControllerImplMXBean, AutoCloseable {
@@ -75,4 +75,8 @@ interface ConfigTransactionControllerInternal extends
ServiceReferenceWritableRegistry getWritableRegistry();
+ TransactionIdentifier getTransactionIdentifier();
+
+ @Override
+ void close();
}
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java
new file mode 100644
index 0000000000..ba7ab7fcba
--- /dev/null
+++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java
@@ -0,0 +1,122 @@
+package org.opendaylight.controller.config.manager.impl;
+
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+import java.util.concurrent.TimeUnit;
+
+public class DeadlockMonitor implements AutoCloseable {
+ private static final Logger logger = LoggerFactory.getLogger(DeadlockMonitorRunnable.class);
+
+ private static final long WARN_AFTER_MILLIS = 5000;
+
+ private final TransactionIdentifier transactionIdentifier;
+ private final DeadlockMonitorRunnable thread;
+ @GuardedBy("this")
+ private ModuleIdentifierWithNanos moduleIdentifierWithNanos = new ModuleIdentifierWithNanos();
+
+ public DeadlockMonitor(TransactionIdentifier transactionIdentifier) {
+ this.transactionIdentifier = transactionIdentifier;
+ thread = new DeadlockMonitorRunnable();
+ thread.start();
+ }
+
+ public synchronized void setCurrentlyInstantiatedModule(ModuleIdentifier currentlyInstantiatedModule) {
+ this.moduleIdentifierWithNanos = new ModuleIdentifierWithNanos(currentlyInstantiatedModule);
+ }
+
+ public boolean isAlive() {
+ return thread.isAlive();
+ }
+
+ @Override
+ public void close() {
+ thread.interrupt();
+ }
+
+ @Override
+ public String toString() {
+ return "DeadlockMonitor{" + transactionIdentifier + '}';
+ }
+
+ private class DeadlockMonitorRunnable extends Thread {
+
+ private DeadlockMonitorRunnable() {
+ super(DeadlockMonitor.this.toString());
+ }
+
+ @Override
+ public void run() {
+ ModuleIdentifierWithNanos old = new ModuleIdentifierWithNanos(); // null moduleId
+ while (this.isInterrupted() == false) {
+ ModuleIdentifierWithNanos copy = new ModuleIdentifierWithNanos(DeadlockMonitor.this.moduleIdentifierWithNanos);
+ if (old.moduleIdentifier == null) {
+ // started
+ old = copy;
+ } else if (old.moduleIdentifier != null && old.equals(copy)) {
+ // is the getInstance() running longer than WARN_AFTER_MILLIS ?
+ long runningTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - copy.nanoTime);
+ if (runningTime > WARN_AFTER_MILLIS) {
+ logger.warn("{} did not finish after {} ms", copy.moduleIdentifier, runningTime);
+ }
+ }
+ try {
+ sleep(1000);
+ } catch (InterruptedException e) {
+ interrupt();
+ }
+ }
+ logger.trace("Exiting {}", this);
+ }
+
+ @Override
+ public String toString() {
+ return "DeadLockMonitorRunnable{" + transactionIdentifier + "}";
+ }
+ }
+
+ private class ModuleIdentifierWithNanos {
+ @Nullable
+ private final ModuleIdentifier moduleIdentifier;
+ private final long nanoTime;
+
+ private ModuleIdentifierWithNanos() {
+ moduleIdentifier = null;
+ nanoTime = System.nanoTime();
+ }
+
+ private ModuleIdentifierWithNanos(ModuleIdentifier moduleIdentifier) {
+ this.moduleIdentifier = moduleIdentifier;
+ nanoTime = System.nanoTime();
+ }
+
+ private ModuleIdentifierWithNanos(ModuleIdentifierWithNanos copy) {
+ moduleIdentifier = copy.moduleIdentifier;
+ nanoTime = copy.nanoTime;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ModuleIdentifierWithNanos that = (ModuleIdentifierWithNanos) o;
+
+ if (nanoTime != that.nanoTime) return false;
+ if (moduleIdentifier != null ? !moduleIdentifier.equals(that.moduleIdentifier) : that.moduleIdentifier != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = moduleIdentifier != null ? moduleIdentifier.hashCode() : 0;
+ result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32));
+ return result;
+ }
+ }
+}
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalInfo.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalInfo.java
index 941aec1096..fd6262cb8c 100644
--- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalInfo.java
+++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalInfo.java
@@ -10,6 +10,7 @@ package org.opendaylight.controller.config.manager.impl;
import javax.annotation.Nullable;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
import org.opendaylight.controller.config.manager.impl.jmx.ModuleJMXRegistrator;
import org.opendaylight.controller.config.manager.impl.jmx.RootRuntimeBeanRegistratorImpl;
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java
index e3057a1179..c229450c30 100644
--- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java
+++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java
@@ -118,7 +118,7 @@ final class DependencyResolverImpl implements DependencyResolver,
}
}
- // transalate from serviceref to module ON
+ // translate from serviceref to module ON
private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) {
if (ObjectNameUtil.isServiceReference(dependentReadOnlyON)) {
String serviceQName = ObjectNameUtil.getServiceQName(dependentReadOnlyON);
@@ -214,7 +214,7 @@ final class DependencyResolverImpl implements DependencyResolver,
return maxDependencyDepth;
}
- public void countMaxDependencyDepth(DependencyResolverManager manager) {
+ void countMaxDependencyDepth(DependencyResolverManager manager) {
transactionStatus.checkCommitted();
if (maxDependencyDepth == null) {
maxDependencyDepth = getMaxDepth(this, manager,
@@ -257,4 +257,5 @@ final class DependencyResolverImpl implements DependencyResolver,
public ModuleIdentifier getIdentifier() {
return name;
}
+
}
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java
index c115934d37..b99bf8330e 100644
--- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java
+++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java
@@ -7,45 +7,57 @@
*/
package org.opendaylight.controller.config.manager.impl.dependencyresolver;
+import com.google.common.reflect.AbstractInvocationHandler;
+import com.google.common.reflect.Reflection;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.DependencyResolverFactory;
import org.opendaylight.controller.config.api.JmxAttribute;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.DeadlockMonitor;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
import org.opendaylight.controller.config.manager.impl.TransactionStatus;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
import javax.annotation.concurrent.GuardedBy;
import javax.management.InstanceAlreadyExistsException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import static com.google.common.base.Preconditions.checkState;
+
/**
* Holds information about modules being created and destroyed within this
* transaction. Observes usage of DependencyResolver within modules to figure
* out dependency tree.
*/
-public class DependencyResolverManager implements TransactionHolder, DependencyResolverFactory {
+public class DependencyResolverManager implements DependencyResolverFactory, AutoCloseable {
@GuardedBy("this")
private final Map moduleIdentifiersToDependencyResolverMap = new HashMap<>();
private final ModulesHolder modulesHolder;
private final TransactionStatus transactionStatus;
private final ServiceReferenceReadableRegistry readableRegistry;
private final CodecRegistry codecRegistry;
+ private final DeadlockMonitor deadlockMonitor;
- public DependencyResolverManager(String transactionName,
+ public DependencyResolverManager(TransactionIdentifier transactionIdentifier,
TransactionStatus transactionStatus, ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) {
- this.modulesHolder = new ModulesHolder(transactionName);
+ this.modulesHolder = new ModulesHolder(transactionIdentifier);
this.transactionStatus = transactionStatus;
this.readableRegistry = readableRegistry;
this.codecRegistry = codecRegistry;
+ this.deadlockMonitor = new DeadlockMonitor(transactionIdentifier);
}
@Override
@@ -88,7 +100,6 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR
return result;
}
- @Override
public ModuleInternalTransactionalInfo destroyModule(
ModuleIdentifier moduleIdentifier) {
transactionStatus.checkNotCommitted();
@@ -99,45 +110,85 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR
}
// protect write access
- @Override
+
public void put(
- ModuleInternalTransactionalInfo moduleInternalTransactionalInfo) {
+ final ModuleIdentifier moduleIdentifier,
+ final Module module,
+ ModuleFactory moduleFactory,
+ ModuleInternalInfo maybeOldInternalInfo,
+ TransactionModuleJMXRegistration transactionModuleJMXRegistration,
+ boolean isDefaultBean) {
transactionStatus.checkNotCommitted();
+
+ Class extends Module> moduleClass = Module.class;
+ if (module instanceof RuntimeBeanRegistratorAwareModule) {
+ moduleClass = RuntimeBeanRegistratorAwareModule.class;
+ }
+ Module proxiedModule = Reflection.newProxy(moduleClass, new AbstractInvocationHandler() {
+ // optimization: subsequent calls to getInstance MUST return the same value during transaction,
+ // so it is safe to cache the response
+ private Object cachedInstance;
+
+ @Override
+ protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+ boolean isGetInstance = method.getName().equals("getInstance");
+ if (isGetInstance) {
+ if (cachedInstance != null) {
+ return cachedInstance;
+ }
+
+ checkState(deadlockMonitor.isAlive(), "Deadlock monitor is not alive");
+ deadlockMonitor.setCurrentlyInstantiatedModule(moduleIdentifier);
+ }
+ try {
+ Object response = method.invoke(module, args);
+ if (isGetInstance) {
+ cachedInstance = response;
+ }
+ return response;
+ } catch(InvocationTargetException e) {
+ throw e.getCause();
+ } finally {
+ if (isGetInstance) {
+ deadlockMonitor.setCurrentlyInstantiatedModule(null);
+ }
+ }
+ }
+ });
+
+
+ ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
+ moduleIdentifier, proxiedModule, moduleFactory,
+ maybeOldInternalInfo, transactionModuleJMXRegistration, isDefaultBean, module);
modulesHolder.put(moduleInternalTransactionalInfo);
}
// wrapped methods:
- @Override
public CommitInfo toCommitInfo() {
return modulesHolder.toCommitInfo();
}
- @Override
public Module findModule(ModuleIdentifier moduleIdentifier,
- JmxAttribute jmxAttributeForReporting) {
+ JmxAttribute jmxAttributeForReporting) {
return modulesHolder.findModule(moduleIdentifier,
jmxAttributeForReporting);
}
- @Override
public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
return modulesHolder.findModuleInternalTransactionalInfo(moduleIdentifier);
}
- @Override
public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
- JmxAttribute jmxAttributeForReporting) {
+ JmxAttribute jmxAttributeForReporting) {
return modulesHolder.findModuleFactory(moduleIdentifier,
jmxAttributeForReporting);
}
- @Override
public Map getAllModules() {
return modulesHolder.getAllModules();
}
- @Override
public void assertNotExists(ModuleIdentifier moduleIdentifier)
throws InstanceAlreadyExistsException {
modulesHolder.assertNotExists(moduleIdentifier);
@@ -145,11 +196,16 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR
public List findAllByFactory(ModuleFactory factory) {
List result = new ArrayList<>();
- for( ModuleInternalTransactionalInfo info : modulesHolder.getAllInfos()) {
+ for (ModuleInternalTransactionalInfo info : modulesHolder.getAllInfos()) {
if (factory.equals(info.getModuleFactory())) {
result.add(info.getIdentifier());
}
}
return result;
}
+
+ public void close() {
+ deadlockMonitor.close();
+ }
+
}
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DestroyedModule.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DestroyedModule.java
similarity index 94%
rename from opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DestroyedModule.java
rename to opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DestroyedModule.java
index e4652c9bb8..2aa74758d4 100644
--- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DestroyedModule.java
+++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DestroyedModule.java
@@ -5,7 +5,7 @@
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.controller.config.manager.impl;
+package org.opendaylight.controller.config.manager.impl.dependencyresolver;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.manager.impl.jmx.ModuleJMXRegistrator;
@@ -31,7 +31,7 @@ public class DestroyedModule implements AutoCloseable,
private final OsgiRegistration osgiRegistration;
private final int orderingIdx;
- DestroyedModule(ModuleIdentifier identifier, AutoCloseable instance,
+ public DestroyedModule(ModuleIdentifier identifier, AutoCloseable instance,
ModuleJMXRegistrator oldJMXRegistrator,
OsgiRegistration osgiRegistration, int orderingIdx) {
this.identifier = identifier;
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalTransactionalInfo.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/ModuleInternalTransactionalInfo.java
similarity index 75%
rename from opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalTransactionalInfo.java
rename to opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/ModuleInternalTransactionalInfo.java
index f598433433..e9f573a05d 100644
--- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalTransactionalInfo.java
+++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/ModuleInternalTransactionalInfo.java
@@ -5,9 +5,10 @@
* 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;
+package org.opendaylight.controller.config.manager.impl.dependencyresolver;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
import org.opendaylight.controller.config.spi.Module;
@@ -18,24 +19,25 @@ import javax.annotation.Nullable;
public class ModuleInternalTransactionalInfo implements Identifiable {
private final ModuleIdentifier name;
- private final Module module;
+ private final Module proxiedModule, realModule;
private final ModuleFactory moduleFactory;
@Nullable
private final ModuleInternalInfo maybeOldInternalInfo;
private final TransactionModuleJMXRegistration transactionModuleJMXRegistration;
private final boolean isDefaultBean;
- ModuleInternalTransactionalInfo(ModuleIdentifier name, Module module,
- ModuleFactory moduleFactory,
- ModuleInternalInfo maybeOldInternalInfo,
- TransactionModuleJMXRegistration transactionModuleJMXRegistration,
- boolean isDefaultBean) {
+ public ModuleInternalTransactionalInfo(ModuleIdentifier name, Module proxiedModule,
+ ModuleFactory moduleFactory,
+ ModuleInternalInfo maybeOldInternalInfo,
+ TransactionModuleJMXRegistration transactionModuleJMXRegistration,
+ boolean isDefaultBean, Module realModule) {
this.name = name;
- this.module = module;
+ this.proxiedModule = proxiedModule;
this.moduleFactory = moduleFactory;
this.maybeOldInternalInfo = maybeOldInternalInfo;
this.transactionModuleJMXRegistration = transactionModuleJMXRegistration;
this.isDefaultBean = isDefaultBean;
+ this.realModule = realModule;
}
@@ -56,8 +58,8 @@ public class ModuleInternalTransactionalInfo implements Identifiable commitMap = new HashMap<>();
@GuardedBy("this")
private final Set unorderedDestroyedFromPreviousTransactions = new HashSet<>();
- ModulesHolder(String transactionName) {
- this.transactionName = transactionName;
+ ModulesHolder(TransactionIdentifier transactionIdentifier) {
+ this.transactionIdentifier = transactionIdentifier;
}
- @Override
+
public CommitInfo toCommitInfo() {
List orderedDestroyedFromPreviousTransactions = new ArrayList<>(
unorderedDestroyedFromPreviousTransactions.size());
@@ -62,43 +61,38 @@ class ModulesHolder implements TransactionHolder {
.get(moduleIdentifier);
JmxAttributeValidationException.checkNotNull(
moduleInternalTransactionalInfo, "Module " + moduleIdentifier
- + "" + " not found in transaction " + transactionName,
+ + "" + " not found in transaction " + transactionIdentifier,
jmxAttributeForReporting);
return moduleInternalTransactionalInfo;
}
- @Override
public Module findModule(ModuleIdentifier moduleIdentifier,
JmxAttribute jmxAttributeForReporting) {
return findModuleInternalTransactionalInfo(moduleIdentifier,
- jmxAttributeForReporting).getModule();
+ jmxAttributeForReporting).getProxiedModule();
}
- @Override
public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
JmxAttribute jmxAttributeForReporting) {
return findModuleInternalTransactionalInfo(moduleIdentifier,
jmxAttributeForReporting).getModuleFactory();
}
- @Override
public Map getAllModules() {
Map result = new HashMap<>();
for (ModuleInternalTransactionalInfo entry : commitMap.values()) {
ModuleIdentifier name = entry.getIdentifier();
- result.put(name, entry.getModule());
+ result.put(name, entry.getProxiedModule());
}
return result;
}
- @Override
public void put(
ModuleInternalTransactionalInfo moduleInternalTransactionalInfo) {
commitMap.put(moduleInternalTransactionalInfo.getIdentifier(),
moduleInternalTransactionalInfo);
}
- @Override
public ModuleInternalTransactionalInfo destroyModule(
ModuleIdentifier moduleIdentifier) {
ModuleInternalTransactionalInfo found = commitMap.remove(moduleIdentifier);
@@ -111,7 +105,6 @@ class ModulesHolder implements TransactionHolder {
return found;
}
- @Override
public void assertNotExists(ModuleIdentifier moduleIdentifier)
throws InstanceAlreadyExistsException {
if (commitMap.containsKey(moduleIdentifier)) {
@@ -124,7 +117,6 @@ class ModulesHolder implements TransactionHolder {
return commitMap.values();
}
- @Override
public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
ModuleInternalTransactionalInfo found = commitMap.get(moduleIdentifier);
if (found == null) {
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/TransactionHolder.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/TransactionHolder.java
deleted file mode 100644
index bccd453af0..0000000000
--- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/TransactionHolder.java
+++ /dev/null
@@ -1,41 +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.dependencyresolver;
-
-import org.opendaylight.controller.config.api.JmxAttribute;
-import org.opendaylight.controller.config.api.ModuleIdentifier;
-import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
-import org.opendaylight.controller.config.spi.Module;
-import org.opendaylight.controller.config.spi.ModuleFactory;
-
-import javax.management.InstanceAlreadyExistsException;
-import java.util.Map;
-
-interface TransactionHolder {
- CommitInfo toCommitInfo();
-
- Module findModule(ModuleIdentifier moduleIdentifier,
- JmxAttribute jmxAttributeForReporting);
-
- ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
- JmxAttribute jmxAttributeForReporting);
-
- Map getAllModules();
-
- void put(ModuleInternalTransactionalInfo moduleInternalTransactionalInfo);
-
- ModuleInternalTransactionalInfo destroyModule(
- ModuleIdentifier moduleIdentifier);
-
- void assertNotExists(ModuleIdentifier moduleIdentifier)
- throws InstanceAlreadyExistsException;
-
- ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier);
-
-}
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/ModuleInfoBundleTracker.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/ModuleInfoBundleTracker.java
index 8ba290f306..a8fdfda7d7 100644
--- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/ModuleInfoBundleTracker.java
+++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/ModuleInfoBundleTracker.java
@@ -20,7 +20,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
-import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Collection;
import java.util.LinkedList;
@@ -98,31 +97,26 @@ public final class ModuleInfoBundleTracker implements BundleTrackerCustomizer loadClass(String moduleInfoClass, Bundle bundle) {
diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManagerTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManagerTest.java
index 63a66e96eb..123e52f675 100644
--- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManagerTest.java
+++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManagerTest.java
@@ -7,24 +7,27 @@
*/
package org.opendaylight.controller.config.manager.impl.dependencyresolver;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-
-import java.util.Arrays;
-import java.util.List;
-
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.api.JmxAttribute;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
import org.opendaylight.controller.config.manager.impl.TransactionStatus;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
public class DependencyResolverManagerTest {
@@ -42,7 +45,7 @@ public class DependencyResolverManagerTest {
public void setUp() {
transactionStatus = mock(TransactionStatus.class);
ServiceReferenceReadableRegistry mockedRegistry = mock(ServiceReferenceReadableRegistry.class);
- tested = new DependencyResolverManager("txName", transactionStatus, mockedRegistry, null);
+ tested = new DependencyResolverManager(new TransactionIdentifier("txName"), transactionStatus, mockedRegistry, null);
doNothing().when(transactionStatus).checkCommitStarted();
doNothing().when(transactionStatus).checkNotCommitted();
}
@@ -87,10 +90,18 @@ public class DependencyResolverManagerTest {
private static void mockGetInstance(DependencyResolverManager tested,
ModuleIdentifier moduleIdentifier) {
- ModuleInternalTransactionalInfo mock = mock(ModuleInternalTransactionalInfo.class);
- doReturn(moduleIdentifier).when(mock).getIdentifier();
- doReturn(mockedModule()).when(mock).getModule();
- tested.put(mock);
+
+ ModuleFactory moduleFactory = mock(ModuleFactory.class);
+ ModuleInternalInfo maybeOldInternalInfo = null;
+ TransactionModuleJMXRegistration transactionModuleJMXRegistration = null;
+ boolean isDefaultBean = false;
+
+ tested.put(moduleIdentifier,
+ mockedModule(),
+ moduleFactory,
+ maybeOldInternalInfo,
+ transactionModuleJMXRegistration,
+ isDefaultBean);
}
private static Module mockedModule() {
diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModule.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModule.java
index f4ba5ef887..df6dce1243 100644
--- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModule.java
+++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModule.java
@@ -7,15 +7,7 @@
*/
package org.opendaylight.controller.config.manager.testingservices.parallelapsp;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import java.io.Closeable;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.NotThreadSafe;
-import javax.management.ObjectName;
-
+import com.google.common.base.Strings;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.JmxAttribute;
import org.opendaylight.controller.config.api.ModuleIdentifier;
@@ -26,7 +18,13 @@ import org.opendaylight.controller.config.spi.Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Strings;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import javax.management.ObjectName;
+import java.io.Closeable;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
/**
* Represents service that has dependency to thread pool.
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 4e9ce009b4..28408abed2 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
@@ -326,7 +326,7 @@ public class SimpleConfigurationTest extends AbstractConfigTest {
}
@Test
- public void testAbort() {
+ public void testAbort() throws InstanceAlreadyExistsException, ValidationException {
ConfigTransactionJMXClient transaction = configRegistryClient
.createTransaction();
assertEquals(1, configRegistryClient.getOpenConfigs().size());
@@ -336,14 +336,14 @@ public class SimpleConfigurationTest extends AbstractConfigTest {
transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME,
fixed1);
fail();
- } catch (Exception e) {
- assertTrue(e.getCause() instanceof InstanceNotFoundException);
+ } catch (IllegalStateException e) {
+ assertEquals("Configuration was aborted", e.getMessage());
}
try {
transaction.validateConfig();
fail();
- } catch (Exception e) {
- assertTrue(e.getCause() instanceof InstanceNotFoundException);
+ } catch (IllegalStateException e) {
+ assertEquals("Configuration was aborted", e.getMessage());
}
assertEquals(0, configRegistryClient.getOpenConfigs().size());
}
diff --git a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/AutoCloseableEventExecutor.java b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/AutoCloseableEventExecutor.java
new file mode 100644
index 0000000000..69ea51f3a5
--- /dev/null
+++ b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/AutoCloseableEventExecutor.java
@@ -0,0 +1,52 @@
+/*
+ * 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 com.google.common.reflect.AbstractInvocationHandler;
+import com.google.common.reflect.Reflection;
+import io.netty.util.concurrent.EventExecutor;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.TimeUnit;
+
+public interface AutoCloseableEventExecutor extends EventExecutor, AutoCloseable {
+
+
+ public static class CloseableEventExecutorMixin implements AutoCloseable {
+ public static final int DEFAULT_SHUTDOWN_SECONDS = 1;
+ private final EventExecutor eventExecutor;
+
+ public CloseableEventExecutorMixin(EventExecutor eventExecutor) {
+ this.eventExecutor = eventExecutor;
+ }
+
+ @Override
+ public void close() {
+ eventExecutor.shutdownGracefully(0, DEFAULT_SHUTDOWN_SECONDS, TimeUnit.SECONDS);
+ }
+
+
+ public static AutoCloseable createCloseableProxy(final EventExecutor eventExecutor) {
+ final CloseableEventExecutorMixin closeableGlobalEventExecutorMixin =
+ new CloseableEventExecutorMixin(eventExecutor);
+ return Reflection.newProxy(AutoCloseableEventExecutor.class, new AbstractInvocationHandler() {
+ @Override
+ protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+ if (method.getName().equals("close")) {
+ closeableGlobalEventExecutorMixin.close();
+ return null;
+ } else {
+ return method.invoke(eventExecutor, args);
+ }
+ }
+ });
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java
index 2c4c211784..8751a80b8d 100644
--- a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java
+++ b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java
@@ -17,13 +17,9 @@
*/
package org.opendaylight.controller.config.yang.netty.eventexecutor;
-import com.google.common.reflect.AbstractInvocationHandler;
-import com.google.common.reflect.Reflection;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.GlobalEventExecutor;
-
-import java.lang.reflect.Method;
-import java.util.concurrent.TimeUnit;
+import org.opendaylight.controller.config.yang.netty.eventexecutor.AutoCloseableEventExecutor.CloseableEventExecutorMixin;
public final class GlobalEventExecutorModule extends
org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractGlobalEventExecutorModule {
@@ -46,35 +42,10 @@ public final class GlobalEventExecutorModule extends
@Override
public java.lang.AutoCloseable createInstance() {
- final CloseableGlobalEventExecutorMixin closeableGlobalEventExecutorMixin =
- new CloseableGlobalEventExecutorMixin(GlobalEventExecutor.INSTANCE);
- return Reflection.newProxy(AutoCloseableEventExecutor.class, new AbstractInvocationHandler() {
- @Override
- protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
- if (method.getName().equals("close")) {
- closeableGlobalEventExecutorMixin.close();
- return null;
- } else {
- return method.invoke(GlobalEventExecutor.INSTANCE, args);
- }
- }
- });
+ EventExecutor eventExecutor = GlobalEventExecutor.INSTANCE;
+ return CloseableEventExecutorMixin.createCloseableProxy(eventExecutor);
}
- public static interface AutoCloseableEventExecutor extends EventExecutor, AutoCloseable {
-
- }
- public static class CloseableGlobalEventExecutorMixin implements AutoCloseable {
- private final GlobalEventExecutor eventExecutor;
- public CloseableGlobalEventExecutorMixin(GlobalEventExecutor eventExecutor) {
- this.eventExecutor = eventExecutor;
- }
-
- @Override
- public void close() {
- eventExecutor.shutdownGracefully(0, 1, TimeUnit.SECONDS);
- }
- }
}
diff --git a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModule.java b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModule.java
new file mode 100644
index 0000000000..27ca63fe4a
--- /dev/null
+++ b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModule.java
@@ -0,0 +1,36 @@
+/*
+ * 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 io.netty.util.concurrent.EventExecutor;
+import io.netty.util.concurrent.ImmediateEventExecutor;
+import org.opendaylight.controller.config.yang.netty.eventexecutor.AutoCloseableEventExecutor.CloseableEventExecutorMixin;
+
+public final class ImmediateEventExecutorModule extends org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractImmediateEventExecutorModule {
+
+ public ImmediateEventExecutorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public ImmediateEventExecutorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ ImmediateEventExecutorModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ protected void customValidation() {
+ // Add custom validation for module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ EventExecutor eventExecutor = ImmediateEventExecutor.INSTANCE;
+ return CloseableEventExecutorMixin.createCloseableProxy(eventExecutor);
+ }
+}
diff --git a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleFactory.java b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleFactory.java
new file mode 100644
index 0000000000..b3ec67bbf5
--- /dev/null
+++ b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleFactory.java
@@ -0,0 +1,29 @@
+/*
+ * 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 org.opendaylight.controller.config.api.DependencyResolver;
+import org.osgi.framework.BundleContext;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class ImmediateEventExecutorModuleFactory extends org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractImmediateEventExecutorModuleFactory {
+ public static final String SINGLETON_NAME = "singleton";
+
+ @Override
+ public ImmediateEventExecutorModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, ImmediateEventExecutorModule oldModule, AutoCloseable oldInstance, BundleContext bundleContext) {
+ checkArgument(SINGLETON_NAME.equals(instanceName), "Illegal instance name '" + instanceName + "', only allowed name is " + SINGLETON_NAME);
+ return super.instantiateModule(instanceName, dependencyResolver, oldModule, oldInstance, bundleContext);
+ }
+
+ @Override
+ public ImmediateEventExecutorModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+ checkArgument(SINGLETON_NAME.equals(instanceName), "Illegal instance name '" + instanceName + "', only allowed name is " + SINGLETON_NAME);
+ return super.instantiateModule(instanceName, dependencyResolver, bundleContext);
+ }
+}
diff --git a/opendaylight/config/netty-event-executor-config/src/main/yang/netty-event-executor.yang b/opendaylight/config/netty-event-executor-config/src/main/yang/netty-event-executor.yang
index e9d1da3f2d..8d812adc4d 100644
--- a/opendaylight/config/netty-event-executor-config/src/main/yang/netty-event-executor.yang
+++ b/opendaylight/config/netty-event-executor-config/src/main/yang/netty-event-executor.yang
@@ -36,7 +36,18 @@ module netty-event-executor {
augment "/config:modules/config:module/config:configuration" {
case netty-global-event-executor {
when "/config:modules/config:module/config:type = 'netty-global-event-executor'";
+ }
+ }
+ identity netty-immediate-event-executor {
+ base config:module-type;
+ config:provided-service netty:netty-event-executor;
+ config:java-name-prefix ImmediateEventExecutor;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case netty-immediate-event-executor {
+ when "/config:modules/config:module/config:type = 'netty-immediate-event-executor'";
}
}
}
diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml
index 562db98301..6cc06ba705 100644
--- a/opendaylight/md-sal/pom.xml
+++ b/opendaylight/md-sal/pom.xml
@@ -120,7 +120,7 @@
${user.name}-private-view
java
3.0.0
- 0.7.1-SNAPSHOT
+ 0.8.1-SNAPSHOT
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java
index aa846ff78d..65f1ff2fe3 100644
--- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java
+++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java
@@ -7,24 +7,19 @@
*/
package org.opendaylight.controller.sal.binding.api.data;
-import java.util.concurrent.Future;
-
import org.opendaylight.controller.md.sal.common.api.data.DataChangePublisher;
import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransactionFactory;
import org.opendaylight.controller.md.sal.common.api.data.DataReader;
import org.opendaylight.controller.sal.binding.api.BindingAwareService;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
/**
* DataBrokerService provides unified access to the data stores available in the
* system.
- *
- *
+ *
+ *
* @see DataProviderService
*/
public interface DataBrokerService extends //
@@ -32,163 +27,37 @@ public interface DataBrokerService extends //
DataModificationTransactionFactory, DataObject>, //
DataReader, DataObject>, //
DataChangePublisher, DataObject, DataChangeListener> {
-
- /**
- * Returns a data from specified Data Store.
- *
- * Returns all the data visible to the consumer from specified Data Store.
- *
- * @param
- * Interface generated from YANG module representing root of data
- * @param store
- * Identifier of the store, from which will be data retrieved
- * @return data visible to the consumer
- */
- @Deprecated
- T getData(DataStoreIdentifier store, Class rootType);
-
- /**
- * Returns a filtered subset of data from specified Data Store.
- *
- *
- * The filter is modeled as an hierarchy of Java TOs starting with
- * implementation of {@link DataRoot} representing data root. The semantics
- * of the filter tree is the same as filter semantics defined in the NETCONF
- * protocol for rpc operations get
and get-config
- * in Section 6 of RFC6241.
- *
- *
- * @see http://tools.ietf.org/html/rfc6241#section-6
- * @param
- * Interface generated from YANG module representing root of data
- * @param store
- * Identifier of the store, from which will be data retrieved
- * @param filter
- * Data tree filter similar to the NETCONF filter
- * @return
- */
- @Deprecated
- T getData(DataStoreIdentifier store, T filter);
-
- /**
- * Returns a candidate data which are not yet commited.
- *
- *
- * @param
- * Interface generated from YANG module representing root of data
- * @param store
- * Identifier of the store, from which will be data retrieved
- * @return
- */
- @Deprecated
- T getCandidateData(DataStoreIdentifier store, Class rootType);
-
- /**
- * Returns a filtered subset of candidate data from specified Data Store.
- *
- *
- * The filter is modeled as an hierarchy of {@link Node} starting with
- * {@link CompositeNode} representing data root. The semantics of the filter
- * tree is the same as filter semantics defined in the NETCONF protocol for
- * rpc operations get
and get-config
in Section 6
- * of RFC6241.
- *
- *
- * @see http://tools.ietf.org/html/rfc6241#section-6
- * @param
- * Interface generated from YANG module representing root of data
- * @param store
- * Identifier of the store, from which will be data retrieved
- * @param filter
- * A filter data root
- * @return
- */
- @Deprecated
- T getCandidateData(DataStoreIdentifier store, T filter);
-
- /**
- *
- * @param
- * Interface generated from YANG module representing root of data
- * @param store
- * Identifier of the store, in which will be the candidate data
- * modified
- * @param changeSet
- * Modification of data tree.
- * @return Result object containing the modified data tree if the operation
- * was successful, otherwise list of the encountered errors.
- */
- @Deprecated
- RpcResult editCandidateData(DataStoreIdentifier store, DataRoot changeSet);
-
- /**
- * Initiates a two-phase commit of candidate data.
- *
- *
- * The {@link Consumer} could initiate a commit of candidate data
- *
- *
- * The successful commit changes the state of the system and may affect
- * several components.
- *
- *
- * The effects of successful commit of data are described in the
- * specifications and YANG models describing the {@link Provider} components
- * of controller. It is assumed that {@link Consumer} has an understanding
- * of this changes.
- *
- *
- * @see DataCommitHandler for further information how two-phase commit is
- * processed.
- * @param store
- * Identifier of the store, where commit should occur.
- * @return Result of the commit, containing success information or list of
- * encountered errors, if commit was not successful.
- */
- @Deprecated
- Future> commit(DataStoreIdentifier store);
-
- @Deprecated
- DataObject getData(InstanceIdentifier extends DataObject> data);
-
- @Deprecated
- DataObject getConfigurationData(InstanceIdentifier> data);
/**
* Creates a data modification transaction.
- *
+ *
* @return new blank data modification transaction.
*/
- DataModificationTransaction beginTransaction();
-
- @Deprecated
- public void registerChangeListener(InstanceIdentifier extends DataObject> path, DataChangeListener changeListener);
-
- @Deprecated
- public void unregisterChangeListener(InstanceIdentifier extends DataObject> path, DataChangeListener changeListener);
+ @Override
+ DataModificationTransaction beginTransaction();
/**
- * Reads data subtree from configurational store.
- * (Store which is populated by consumer, which is usually used to
+ * Reads data subtree from configurational store.
+ * (Store which is populated by consumer, which is usually used to
* inject state into providers. E.g. Flow configuration)-
- *
+ *
*/
@Override
public DataObject readConfigurationData(InstanceIdentifier extends DataObject> path);
-
+
/**
- * Reads data subtree from operational store.
- * (Store which is populated by providers, which is usually used to
+ * Reads data subtree from operational store.
+ * (Store which is populated by providers, which is usually used to
* capture state of providers. E.g. Topology)
- *
+ *
*/
@Override
public DataObject readOperationalData(InstanceIdentifier extends DataObject> path);
-
+
/**
- * Register a data change listener for particular subtree.
- *
+ * Register a data change listener for particular subtree.
+ *
* Callback is invoked each time data in subtree changes.
- *
+ *
*/
@Override
public ListenerRegistration registerDataChangeListener(
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java
index 16d5a24cb5..48ccbfbc95 100644
--- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java
+++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java
@@ -9,19 +9,15 @@ package org.opendaylight.controller.sal.binding.impl;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLong;
import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;
import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sal.binding.impl.util.BindingAwareDataReaderRouter;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.util.DataObjectReadingUtil;
-import org.opendaylight.yangtools.yang.common.RpcResult;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
@@ -79,68 +75,7 @@ public class DataBrokerImpl extends AbstractDataBroker T getData(DataStoreIdentifier store, Class rootType) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- @Deprecated
- public T getData(DataStoreIdentifier store, T filter) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- @Deprecated
- public T getCandidateData(DataStoreIdentifier store, Class rootType) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- @Deprecated
- public T getCandidateData(DataStoreIdentifier store, T filter) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- @Deprecated
- public RpcResult editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- @Deprecated
- public Future> commit(DataStoreIdentifier store) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- @Deprecated
- public DataObject getData(InstanceIdentifier extends DataObject> data) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- @Deprecated
- public DataObject getConfigurationData(InstanceIdentifier> data) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- @Deprecated
- public void registerChangeListener(InstanceIdentifier extends DataObject> path, DataChangeListener changeListener) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- @Deprecated
- public void unregisterChangeListener(InstanceIdentifier extends DataObject> path,
- DataChangeListener changeListener) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public void close() throws Exception {
+ public void close() {
}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend
deleted file mode 100644
index ee2ade5863..0000000000
--- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend
+++ /dev/null
@@ -1,66 +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.sal.binding.impl
-
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.common.DataStoreIdentifier
-import org.opendaylight.yangtools.yang.binding.DataRoot
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener
-
-abstract class DeprecatedDataAPISupport implements DataProviderService {
-
- @Deprecated
- override commit(DataStoreIdentifier store) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override getCandidateData(DataStoreIdentifier store, Class rootType) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override T getCandidateData(DataStoreIdentifier store, T filter) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override getConfigurationData(InstanceIdentifier> data) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override getData(DataStoreIdentifier store, Class rootType) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override T getData(DataStoreIdentifier store, T filter) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override getData(InstanceIdentifier extends DataObject> path) {
- return readOperationalData(path);
- }
-
- override registerChangeListener(InstanceIdentifier extends DataObject> path, DataChangeListener changeListener) {
- }
-
- override unregisterChangeListener(InstanceIdentifier extends DataObject> path,
- DataChangeListener changeListener) {
- }
-
-}
diff --git a/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalConsumerInstance.java b/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalConsumerInstance.java
index 77b411002b..64c1ad3ab4 100644
--- a/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalConsumerInstance.java
+++ b/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalConsumerInstance.java
@@ -7,23 +7,18 @@
*/
package org.opendaylight.controller.md.sal.binding.util;
-import java.util.concurrent.Future;
-
import org.opendaylight.controller.sal.binding.api.NotificationListener;
import org.opendaylight.controller.sal.binding.api.NotificationService;
import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.Notification;
import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.common.RpcResult;
import com.google.common.base.Preconditions;
@@ -114,72 +109,11 @@ public abstract class AbstractBindingSalConsumerInstance T getData(DataStoreIdentifier store, Class rootType) {
- return getDataBrokerChecked().getData(store, rootType);
- }
-
- @Override
- @Deprecated
- public T getData(DataStoreIdentifier store, T filter) {
- return getDataBrokerChecked().getData(store, filter);
- }
-
- @Override
- @Deprecated
- public T getCandidateData(DataStoreIdentifier store, Class rootType) {
- return getDataBrokerChecked().getCandidateData(store, rootType);
- }
-
- @Override
- @Deprecated
- public T getCandidateData(DataStoreIdentifier store, T filter) {
- return getDataBrokerChecked().getCandidateData(store, filter);
- }
-
- @Override
- @Deprecated
- public RpcResult editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
- return getDataBrokerChecked().editCandidateData(store, changeSet);
- }
-
- @Override
- @Deprecated
- public Future> commit(DataStoreIdentifier store) {
- return getDataBrokerChecked().commit(store);
- }
-
- @Override
- @Deprecated
- public DataObject getData(InstanceIdentifier extends DataObject> data) {
- return getDataBrokerChecked().getData(data);
- }
-
- @Override
- @Deprecated
- public DataObject getConfigurationData(InstanceIdentifier> data) {
- return getDataBrokerChecked().getConfigurationData(data);
- }
-
@Override
public DataModificationTransaction beginTransaction() {
return getDataBrokerChecked().beginTransaction();
}
- @Override
- @Deprecated
- public void registerChangeListener(InstanceIdentifier extends DataObject> path, DataChangeListener changeListener) {
- getDataBrokerChecked().registerChangeListener(path, changeListener);
- }
-
- @Override
- @Deprecated
- public void unregisterChangeListener(InstanceIdentifier extends DataObject> path,
- DataChangeListener changeListener) {
- getDataBrokerChecked().unregisterChangeListener(path, changeListener);
- }
-
@Override
@Deprecated
public DataObject readConfigurationData(InstanceIdentifier extends DataObject> path) {
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java
index 939ff95135..30f4fc03cb 100644
--- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java
+++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java
@@ -24,8 +24,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
* this is responsibility of the coordinator (broker or some component of the
* broker).
*
- * The commit handlers are responsible for changing the internal state of the
- * provider to reflect the commited changes in data.
+ * Commit handlers are responsible for changing the internal state of the
+ * provider to reflect the committed changes in data.
*
* Two-phase commit
*
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java
index 33de1d83da..e201f8835b 100644
--- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java
+++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java
@@ -59,7 +59,7 @@ public class TwoPhaseCommit, D extends Object, DCL extends Dat
.addAll(transaction.getCreatedOperationalData().keySet())
.addAll(transaction.getRemovedOperationalData()).build();
- log.trace("Transaction: {} Affected Subtrees:", transactionId, changedPaths);
+ log.trace("Transaction: {} Affected Subtrees: {}", transactionId, changedPaths);
// The transaction has no effects, let's just shortcut it
if (changedPaths.isEmpty()) {
@@ -124,7 +124,7 @@ public class TwoPhaseCommit
, D extends Object, DCL extends Dat
captureFinalState(listeners);
- log.trace("Transaction: {} Notifying listeners.");
+ log.trace("Transaction: {} Notifying listeners.", transactionId);
publishDataChangeEvent(listeners);
return Rpcs. getRpcResult(true, TransactionStatus.COMMITED,
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementation.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementation.java
index 0299505cde..6b1030a815 100644
--- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementation.java
+++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementation.java
@@ -16,11 +16,11 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
/**
- * {@link Provider}'s implementation of rpc.
- *
- * In order to expose the rpc to other components, the provider MUST register
- * concrete implementation of this interface
- *
+ * {@link Provider}'s implementation of an RPC.
+ *
+ * In order to expose an RPC to other components, the provider MUST register
+ * a concrete implementation of this interface.
+ *
* The registration could be done by :
*
* - returning an instance of implementation in the return value of
@@ -29,9 +29,9 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
* arguments to the
* {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}
*
- *
+ *
* The simplified process of the invocation of rpc is following:
- *
+ *
*
* - {@link Consumer} invokes
* {@link ConsumerSession#rpc(QName, CompositeNode)}
@@ -42,31 +42,31 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
* {@link RpcResult}
*
- {@link Broker} returns the {@link RpcResult} to {@link Consumer}
*
- *
- *
+ *
+ *
*/
public interface RpcImplementation extends Provider.ProviderFunctionality {
/**
* A set of rpc types supported by implementation.
- *
+ *
* The set of rpc {@link QName}s which are supported by this implementation.
* This set is used, when {@link Provider} is registered to the SAL, to
* register and expose the implementation of the returned rpcs.
- *
+ *
* @return Set of QNames identifying supported RPCs
*/
Set getSupportedRpcs();
/**
* Invokes a implementation of specified rpc.
- *
- *
+ *
+ *
* @param rpc
* Rpc to be invoked
* @param input
* Input data for rpc.
- *
+ *
* @throws IllegalArgumentException
*
* - If rpc is null.
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java
index abf822087e..f380c27373 100644
--- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java
+++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java
@@ -44,9 +44,6 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
-import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -57,7 +54,6 @@ import com.google.common.collect.ImmutableSet;
public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator implements //
DataStore, //
- SchemaServiceListener, //
SchemaContextListener, //
AutoCloseable {
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java
index 6fe56c87ed..416f1941c1 100644
--- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java
+++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java
@@ -8,19 +8,16 @@
package org.opendaylight.controller.sal.restconf.binding.impl;
import java.net.URL;
-import java.util.concurrent.Future;
+
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
import org.opendaylight.yangtools.restconf.client.api.RestconfClientContextFactory;
import org.opendaylight.yangtools.restconf.client.api.UnsupportedProtocolException;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
import org.opendaylight.yangtools.yang.model.api.SchemaContextHolder;
import org.slf4j.Logger;
@@ -35,45 +32,6 @@ public class DataBrokerServiceImpl implements DataBrokerService {
public DataBrokerServiceImpl(URL baseUrl, BindingIndependentMappingService mappingService, SchemaContextHolder schemaContextHolder) throws UnsupportedProtocolException {
this.restconfClientContext = restconfClientContextFactory.getRestconfClientContext(baseUrl, mappingService, schemaContextHolder);
}
- @Override
- public T getData(DataStoreIdentifier store, Class rootType) {
- return null;
- }
-
- @Override
- public T getData(DataStoreIdentifier store, T filter) {
- return null;
- }
-
- @Override
- public T getCandidateData(DataStoreIdentifier store, Class rootType) {
- return null;
- }
-
- @Override
- public T getCandidateData(DataStoreIdentifier store, T filter) {
- return null;
- }
-
- @Override
- public RpcResult editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
- return null;
- }
-
- @Override
- public Future> commit(DataStoreIdentifier store) {
- return null;
- }
-
- @Override
- public DataObject getData(InstanceIdentifier extends DataObject> data) {
- return null;
- }
-
- @Override
- public DataObject getConfigurationData(InstanceIdentifier> data) {
- return null;
- }
@Override
public DataModificationTransaction beginTransaction() {
@@ -81,16 +39,6 @@ public class DataBrokerServiceImpl implements DataBrokerService {
return null;
}
- @Override
- public void registerChangeListener(InstanceIdentifier extends DataObject> path, DataChangeListener changeListener) {
-
- }
-
- @Override
- public void unregisterChangeListener(InstanceIdentifier extends DataObject> path, DataChangeListener changeListener) {
-
- }
-
@Override
public DataObject readConfigurationData(InstanceIdentifier extends DataObject> path) {
//TODO implementation using restconf-client
@@ -109,9 +57,4 @@ public class DataBrokerServiceImpl implements DataBrokerService {
//TODO implementation using restconf-client
return null;
}
-
-
-
-
-
}
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java
index e31d576d01..003ad9853a 100644
--- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java
+++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java
@@ -14,7 +14,6 @@ import java.util.concurrent.Future;
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.controller.sal.restconf.broker.listeners.RemoteDataChangeNotificationListener;
import org.opendaylight.controller.sal.restconf.broker.tools.RemoteStreamTools;
import org.opendaylight.controller.sal.restconf.broker.transactions.RemoteDataModificationTransaction;
@@ -28,7 +27,6 @@ import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo;
import org.opendaylight.yangtools.restconf.client.api.event.ListenableEventStreamContext;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
@@ -46,45 +44,6 @@ public class DataBrokerServiceImpl implements DataBrokerService {
this.restconfClientContext = restconfClientContext;
this.salRemoteService = this.restconfClientContext.getRpcServiceContext(SalRemoteService.class).getRpcService();
}
- @Override
- public T getData(DataStoreIdentifier store, Class rootType) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public T getData(DataStoreIdentifier store, T filter) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public T getCandidateData(DataStoreIdentifier store, Class rootType) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public T getCandidateData(DataStoreIdentifier store, T filter) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public RpcResult editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public Future> commit(DataStoreIdentifier store) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public DataObject getData(InstanceIdentifier extends DataObject> data) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public DataObject getConfigurationData(InstanceIdentifier> data) {
- throw new UnsupportedOperationException("Deprecated");
- }
@Override
public DataModificationTransaction beginTransaction() {
@@ -94,16 +53,6 @@ public class DataBrokerServiceImpl implements DataBrokerService {
return remoteDataModificationTransaction;
}
- @Override
- public void registerChangeListener(InstanceIdentifier extends DataObject> path, DataChangeListener changeListener) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public void unregisterChangeListener(InstanceIdentifier extends DataObject> path, DataChangeListener changeListener) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
@Override
public DataObject readConfigurationData(InstanceIdentifier extends DataObject> path) {
try {
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Commit.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Commit.java
index 6391a1edad..b3327f54fd 100644
--- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Commit.java
+++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Commit.java
@@ -57,7 +57,8 @@ public class Commit extends AbstractConfigNetconfOperation {
try {
status = this.transactionProvider.commitTransaction();
} catch (final IllegalStateException e) {
- // FIXME: when can IllegalStateException occur?
+ // TODO Illegal state thrown when no transaction yet for user
+ // Throw other exception type, or create transaction automatically
logger.warn("Commit failed: ", e);
final Map errorInfo = new HashMap<>();
errorInfo.put(ErrorTag.operation_failed.name(),
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/Activator.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/Activator.java
index 83029c44e6..5642cc7188 100644
--- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/Activator.java
+++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/Activator.java
@@ -25,7 +25,8 @@ public class Activator implements BundleActivator, YangStoreServiceTracker.YangS
private static final Logger logger = LoggerFactory.getLogger(Activator.class);
private BundleContext context;
- ServiceRegistration osgiRegistration;
+ private ServiceRegistration osgiRegistration;
+ private ConfigRegistryLookupThread configRegistryLookup = null;
@Override
public void start(BundleContext context) throws Exception {
@@ -36,20 +37,42 @@ public class Activator implements BundleActivator, YangStoreServiceTracker.YangS
@Override
public void stop(BundleContext context) throws Exception {
+ if (configRegistryLookup != null) {
+ configRegistryLookup.interrupt();
+ }
}
@Override
public synchronized void onYangStoreAdded(YangStoreService yangStoreService) {
- checkState(osgiRegistration == null, "More than one onYangStoreAdded received");
- NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
- logger.debug("Registering into OSGi");
- osgiRegistration = context.registerService(new String[]{NetconfOperationServiceFactory.class.getName()}, factory,
- new Hashtable());
+ checkState(configRegistryLookup == null, "More than one onYangStoreAdded received");
+ configRegistryLookup = new ConfigRegistryLookupThread(yangStoreService);
+ configRegistryLookup.start();
}
@Override
public synchronized void onYangStoreRemoved() {
- osgiRegistration.unregister();
+ configRegistryLookup.interrupt();
+ if (osgiRegistration != null) {
+ osgiRegistration.unregister();
+ }
osgiRegistration = null;
+ configRegistryLookup = null;
+ }
+
+ private class ConfigRegistryLookupThread extends Thread {
+ private final YangStoreService yangStoreService;
+
+ private ConfigRegistryLookupThread(YangStoreService yangStoreService) {
+ super("config-registry-lookup");
+ this.yangStoreService = yangStoreService;
+ }
+
+ @Override
+ public void run() {
+ NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
+ logger.debug("Registering into OSGi");
+ osgiRegistration = context.registerService(new String[]{NetconfOperationServiceFactory.class.getName()}, factory,
+ new Hashtable());
+ }
}
}
diff --git a/opendaylight/netconf/config-persister-impl/pom.xml b/opendaylight/netconf/config-persister-impl/pom.xml
index 461f22ac2c..daaf60c1d3 100644
--- a/opendaylight/netconf/config-persister-impl/pom.xml
+++ b/opendaylight/netconf/config-persister-impl/pom.xml
@@ -48,6 +48,17 @@
+
+ ${project.groupId}
+ netconf-impl
+ test
+
+
+ ${project.groupId}
+ netconf-util
+ test
+ test-jar
+
org.opendaylight.yangtools
mockito-configuration
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java
index 99d122c3c4..ea2a46dba5 100644
--- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java
+++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java
@@ -9,7 +9,6 @@
package org.opendaylight.controller.netconf.persist.impl;
import com.google.common.base.Preconditions;
-import io.netty.channel.EventLoopGroup;
import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.netconf.api.NetconfMessage;
@@ -29,7 +28,6 @@ import org.xml.sax.SAXException;
import javax.annotation.concurrent.Immutable;
import java.io.IOException;
import java.io.InputStream;
-import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -41,30 +39,12 @@ import java.util.concurrent.TimeoutException;
@Immutable
public class ConfigPusher {
- private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
- private static final int NETCONF_SEND_ATTEMPT_MS_DELAY = 1000;
- private static final int NETCONF_SEND_ATTEMPTS = 20;
-
- private final InetSocketAddress address;
- private final EventLoopGroup nettyThreadGroup;
-
- // Default timeout for netconf becoming stable
- public static final long DEFAULT_MAX_WAIT_FOR_CAPABILITIES_MILLIS = TimeUnit.MINUTES.toMillis(2);
- public static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = 5000;
- private final int delayMillis = 5000;
- private final long maxWaitForCapabilitiesMillis;
- private final long connectionTimeoutMillis;
-
- public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup) {
- this(address, nettyThreadGroup, DEFAULT_MAX_WAIT_FOR_CAPABILITIES_MILLIS, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
- }
+ private static final Logger logger = LoggerFactory.getLogger(ConfigPusher.class);
+
+ private final ConfigPusherConfiguration configuration;
- public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup,
- long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) {
- this.address = address;
- this.nettyThreadGroup = nettyThreadGroup;
- this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
- this.connectionTimeoutMillis = connectionTimeoutMillis;
+ public ConfigPusher(ConfigPusherConfiguration configuration) {
+ this.configuration = configuration;
}
public synchronized LinkedHashMap pushConfigs(
@@ -95,7 +75,7 @@ public class ConfigPusher {
throws InterruptedException {
ConflictingVersionException lastException = null;
- int maxAttempts = 30;
+ int maxAttempts = configuration.netconfPushConfigAttempts;
for (int retryAttempt = 1; retryAttempt <= maxAttempts; retryAttempt++) {
NetconfClient netconfClient = makeNetconfConnection(configSnapshotHolder.getCapabilities());
@@ -106,7 +86,7 @@ public class ConfigPusher {
} catch (ConflictingVersionException e) {
logger.debug("Conflicting version detected, will retry after timeout");
lastException = e;
- Thread.sleep(1000);
+ Thread.sleep(configuration.netconfPushConfigDelayMs);
} catch (RuntimeException e) {
throw new IllegalStateException("Unable to load " + configSnapshotHolder, e);
} finally {
@@ -128,24 +108,25 @@ public class ConfigPusher {
// could be utilized by integration tests
final long pollingStartNanos = System.nanoTime();
- final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(maxWaitForCapabilitiesMillis);
+ final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(configuration.netconfCapabilitiesWaitTimeoutMs);
int attempt = 0;
- NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("unknown", address.getAddress().getHostAddress(),
- Integer.toString(address.getPort()), "tcp", "persister");
+ NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("unknown",
+ configuration.netconfAddress.getAddress().getHostAddress(),
+ Integer.toString(configuration.netconfAddress.getPort()), "tcp", "persister");
Set latestCapabilities = null;
while (System.nanoTime() < deadlineNanos) {
attempt++;
- NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadGroup,
- nettyThreadGroup, additionalHeader, connectionTimeoutMillis);
+ NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(configuration.eventLoopGroup,
+ configuration.eventLoopGroup, additionalHeader, configuration.connectionAttemptTimeoutMs);
NetconfClient netconfClient;
try {
- netconfClient = new NetconfClient(this.toString(), address, delayMillis, netconfClientDispatcher);
+ netconfClient = new NetconfClient(this.toString(), configuration.netconfAddress, configuration.connectionAttemptDelayMs, netconfClientDispatcher);
} catch (IllegalStateException e) {
- logger.debug("Netconf {} was not initialized or is not stable, attempt {}", address, attempt, e);
+ logger.debug("Netconf {} was not initialized or is not stable, attempt {}", configuration.netconfAddress, attempt, e);
netconfClientDispatcher.close();
- Thread.sleep(delayMillis);
+ Thread.sleep(configuration.connectionAttemptDelayMs);
continue;
}
latestCapabilities = netconfClient.getCapabilities();
@@ -159,10 +140,10 @@ public class ConfigPusher {
"Expected but not found: {}, all expected {}, current {}",
attempt, allNotFound, expectedCaps, latestCapabilities);
Util.closeClientAndDispatcher(netconfClient);
- Thread.sleep(delayMillis);
+ Thread.sleep(configuration.connectionAttemptDelayMs);
}
if (latestCapabilities == null) {
- logger.error("Could not connect to the server in {} ms", maxWaitForCapabilitiesMillis);
+ logger.error("Could not connect to the server in {} ms", configuration.netconfCapabilitiesWaitTimeoutMs);
throw new RuntimeException("Could not connect to netconf server");
}
Set allNotFound = computeNotFoundCapabilities(expectedCaps, latestCapabilities);
@@ -229,13 +210,14 @@ public class ConfigPusher {
}
- private static NetconfMessage sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfClient netconfClient)
+ private NetconfMessage sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfClient netconfClient)
throws ConflictingVersionException, IOException {
try {
- NetconfMessage netconfMessage = netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+ NetconfMessage netconfMessage = netconfClient.sendMessage(request,
+ configuration.netconfSendMessageMaxAttempts, configuration.netconfSendMessageDelayMs);
NetconfUtil.checkIsMessageOk(netconfMessage);
return netconfMessage;
- }catch(ConflictingVersionException e) {
+ } catch(ConflictingVersionException e) {
logger.trace("conflicting version detected: {}", e.toString());
throw e;
} catch (RuntimeException | ExecutionException | InterruptedException | TimeoutException e) { // TODO: change NetconfClient#sendMessage to throw checked exceptions
@@ -330,4 +312,5 @@ public class ConfigPusher {
'}';
}
}
+
}
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfiguration.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfiguration.java
new file mode 100644
index 0000000000..aa189f06b4
--- /dev/null
+++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfiguration.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.persist.impl;
+
+import io.netty.channel.EventLoopGroup;
+
+import javax.annotation.concurrent.Immutable;
+import java.net.InetSocketAddress;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Configuration properties for ConfigPusher. Contains delays and timeouts for netconf
+ * connection establishment, netconf capabilities stabilization and configuration push.
+ */
+@Immutable
+public final class ConfigPusherConfiguration {
+
+ public static final long DEFAULT_CONNECTION_ATTEMPT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
+ public static final int DEFAULT_CONNECTION_ATTEMPT_DELAY_MS = 5000;
+
+ public static final int DEFAULT_NETCONF_SEND_MESSAGE_MAX_ATTEMPTS = 20;
+ public static final int DEFAULT_NETCONF_SEND_MESSAGE_DELAY_MS = 1000;
+
+ public static final long DEFAULT_NETCONF_CAPABILITIES_WAIT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(2);
+
+ public static final int DEFAULT_NETCONF_PUSH_CONFIG_ATTEMPTS = 30;
+ public static final long DEFAULT_NETCONF_PUSH_CONFIG_DELAY_MS = TimeUnit.MINUTES.toMillis(1);
+
+ final InetSocketAddress netconfAddress;
+ final EventLoopGroup eventLoopGroup;
+
+ /**
+ * Total time to wait for capability stabilization
+ */
+ final long netconfCapabilitiesWaitTimeoutMs;
+
+ /**
+ * Delay between message send attempts
+ */
+ final int netconfSendMessageDelayMs;
+ /**
+ * Total number attempts to send a message
+ */
+ final int netconfSendMessageMaxAttempts;
+
+ /**
+ * Delay between connection establishment attempts
+ */
+ final int connectionAttemptDelayMs;
+ /**
+ * Total number of attempts to perform connection establishment
+ */
+ final long connectionAttemptTimeoutMs;
+
+ /**
+ * Total number of attempts to push configuration to netconf
+ */
+ final int netconfPushConfigAttempts;
+ /**
+ * Delay between configuration push attempts
+ */
+ final long netconfPushConfigDelayMs;
+
+ ConfigPusherConfiguration(InetSocketAddress netconfAddress, long netconfCapabilitiesWaitTimeoutMs,
+ int netconfSendMessageDelayMs, int netconfSendMessageMaxAttempts, int connectionAttemptDelayMs,
+ long connectionAttemptTimeoutMs, EventLoopGroup eventLoopGroup, int netconfPushConfigAttempts,
+ long netconfPushConfigDelayMs) {
+ this.netconfAddress = netconfAddress;
+ this.netconfCapabilitiesWaitTimeoutMs = netconfCapabilitiesWaitTimeoutMs;
+ this.netconfSendMessageDelayMs = netconfSendMessageDelayMs;
+ this.netconfSendMessageMaxAttempts = netconfSendMessageMaxAttempts;
+ this.connectionAttemptDelayMs = connectionAttemptDelayMs;
+ this.connectionAttemptTimeoutMs = connectionAttemptTimeoutMs;
+ this.eventLoopGroup = eventLoopGroup;
+ this.netconfPushConfigAttempts = netconfPushConfigAttempts;
+ this.netconfPushConfigDelayMs = netconfPushConfigDelayMs;
+ }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java
new file mode 100644
index 0000000000..c26dc8dbe1
--- /dev/null
+++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.persist.impl;
+
+import io.netty.channel.EventLoopGroup;
+
+import java.net.InetSocketAddress;
+
+public class ConfigPusherConfigurationBuilder {
+ InetSocketAddress netconfAddress;
+ EventLoopGroup eventLoopGroup;
+
+ long netconfCapabilitiesWaitTimeoutMs = ConfigPusherConfiguration.DEFAULT_NETCONF_CAPABILITIES_WAIT_TIMEOUT_MS;
+ int netconfSendMessageDelayMs = ConfigPusherConfiguration.DEFAULT_NETCONF_SEND_MESSAGE_DELAY_MS;
+ int netconfSendMessageMaxAttempts = ConfigPusherConfiguration.DEFAULT_NETCONF_SEND_MESSAGE_MAX_ATTEMPTS;
+ int connectionAttemptDelayMs = ConfigPusherConfiguration.DEFAULT_CONNECTION_ATTEMPT_DELAY_MS;
+ long connectionAttemptTimeoutMs = ConfigPusherConfiguration.DEFAULT_CONNECTION_ATTEMPT_TIMEOUT_MS;
+ int netconfPushConfigAttempts = ConfigPusherConfiguration.DEFAULT_NETCONF_PUSH_CONFIG_ATTEMPTS;
+ long netconfPushConfigDelayMs = ConfigPusherConfiguration.DEFAULT_NETCONF_PUSH_CONFIG_DELAY_MS;
+
+ private ConfigPusherConfigurationBuilder() {
+ }
+
+ public static ConfigPusherConfigurationBuilder aConfigPusherConfiguration() {
+ return new ConfigPusherConfigurationBuilder();
+ }
+
+ public ConfigPusherConfigurationBuilder withNetconfAddress(InetSocketAddress netconfAddress) {
+ this.netconfAddress = netconfAddress;
+ return this;
+ }
+
+ public ConfigPusherConfigurationBuilder withNetconfCapabilitiesWaitTimeoutMs(long netconfCapabilitiesWaitTimeoutMs) {
+ this.netconfCapabilitiesWaitTimeoutMs = netconfCapabilitiesWaitTimeoutMs;
+ return this;
+ }
+
+ public ConfigPusherConfigurationBuilder withNetconfSendMessageDelayMs(int netconfSendMessageDelayMs) {
+ this.netconfSendMessageDelayMs = netconfSendMessageDelayMs;
+ return this;
+ }
+
+ public ConfigPusherConfigurationBuilder withNetconfSendMessageMaxAttempts(int netconfSendMessageMaxAttempts) {
+ this.netconfSendMessageMaxAttempts = netconfSendMessageMaxAttempts;
+ return this;
+ }
+
+ public ConfigPusherConfigurationBuilder withConnectionAttemptDelayMs(int connectionAttemptDelayMs) {
+ this.connectionAttemptDelayMs = connectionAttemptDelayMs;
+ return this;
+ }
+
+ public ConfigPusherConfigurationBuilder withConnectionAttemptTimeoutMs(long connectionAttemptTimeoutMs) {
+ this.connectionAttemptTimeoutMs = connectionAttemptTimeoutMs;
+ return this;
+ }
+
+ public ConfigPusherConfigurationBuilder withEventLoopGroup(EventLoopGroup eventLoopGroup) {
+ this.eventLoopGroup = eventLoopGroup;
+ return this;
+ }
+
+ public ConfigPusherConfigurationBuilder withNetconfPushConfigAttempts(int netconfPushConfigAttempts) {
+ this.netconfPushConfigAttempts = netconfPushConfigAttempts;
+ return this;
+ }
+
+ public ConfigPusherConfigurationBuilder withNetconfPushConfigDelayMs(long netconfPushConfigDelayMs) {
+ this.netconfPushConfigDelayMs = netconfPushConfigDelayMs;
+ return this;
+ }
+
+ public ConfigPusherConfiguration build() {
+ ConfigPusherConfiguration configPusherConfiguration = new ConfigPusherConfiguration(netconfAddress,
+ netconfCapabilitiesWaitTimeoutMs, netconfSendMessageDelayMs, netconfSendMessageMaxAttempts,
+ connectionAttemptDelayMs, connectionAttemptTimeoutMs, eventLoopGroup, netconfPushConfigAttempts,
+ netconfPushConfigDelayMs);
+ return configPusherConfiguration;
+ }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java
index f168bb3634..c1cad4a8dd 100644
--- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java
+++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java
@@ -134,7 +134,7 @@ public final class PersisterAggregator implements Persister {
public static PersisterAggregator createFromProperties(PropertiesProviderBaseImpl propertiesProvider) {
List persisterWithConfigurations = new ArrayList<>();
String prefixes = propertiesProvider.getProperty("active");
- if (prefixes.isEmpty() == false) {
+ if (prefixes!=null && prefixes.isEmpty() == false) {
String [] keys = prefixes.split(",");
for (String index: keys) {
persisterWithConfigurations.add(PersisterAggregator.loadConfiguration(index, propertiesProvider));
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
index 1157ddbd83..1246c78fbe 100644
--- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
+++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
@@ -8,10 +8,14 @@
package org.opendaylight.controller.netconf.persist.impl.osgi;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
import org.opendaylight.controller.netconf.persist.impl.ConfigPusher;
+import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfiguration;
+import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfigurationBuilder;
import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator;
import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
import org.osgi.framework.BundleActivator;
@@ -22,16 +26,16 @@ import org.slf4j.LoggerFactory;
import javax.management.MBeanServer;
import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress;
+import java.util.concurrent.ThreadFactory;
import java.util.regex.Pattern;
public class ConfigPersisterActivator implements BundleActivator {
private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterActivator.class);
- private final static MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
- private static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex";
+ public static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex";
- private static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS = "maxWaitForCapabilitiesMillis";
+ public static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS = "maxWaitForCapabilitiesMillis";
public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
@@ -39,43 +43,43 @@ public class ConfigPersisterActivator implements BundleActivator {
public static final String DEFAULT_IGNORED_REGEX = "^urn:ietf:params:xml:ns:netconf:base:1.0";
+ private final MBeanServer platformMBeanServer;
+ private final Optional initialConfigForPusher;
private volatile ConfigPersisterNotificationHandler jmxNotificationHandler;
private Thread initializationThread;
+ private ThreadFactory initializationThreadFactory;
private EventLoopGroup nettyThreadGroup;
private PersisterAggregator persisterAggregator;
+ public ConfigPersisterActivator() {
+ this(new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable initializationRunnable) {
+ return new Thread(initializationRunnable, "ConfigPersister-registrator");
+ }
+ }, ManagementFactory.getPlatformMBeanServer(), null);
+ }
+
+ @VisibleForTesting
+ protected ConfigPersisterActivator(ThreadFactory threadFactory, MBeanServer mBeanServer,
+ ConfigPusherConfiguration initialConfigForPusher) {
+ this.initializationThreadFactory = threadFactory;
+ this.platformMBeanServer = mBeanServer;
+ this.initialConfigForPusher = Optional.fromNullable(initialConfigForPusher);
+ }
+
@Override
public void start(final BundleContext context) throws Exception {
logger.debug("ConfigPersister starting");
PropertiesProviderBaseImpl propertiesProvider = new PropertiesProviderBaseImpl(context);
- String regexProperty = propertiesProvider.getProperty(IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX);
- String regex;
- if (regexProperty != null) {
- regex = regexProperty;
- } else {
- regex = DEFAULT_IGNORED_REGEX;
- }
-
- String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS);
- long maxWaitForCapabilitiesMillis;
- if (timeoutProperty == null) {
- maxWaitForCapabilitiesMillis = ConfigPusher.DEFAULT_MAX_WAIT_FOR_CAPABILITIES_MILLIS;
- } else {
- maxWaitForCapabilitiesMillis = Integer.valueOf(timeoutProperty);
- }
-
- final Pattern ignoredMissingCapabilityRegex = Pattern.compile(regex);
- nettyThreadGroup = new NioEventLoopGroup();
+ final Pattern ignoredMissingCapabilityRegex = getIgnoredCapabilitiesProperty(propertiesProvider);
persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
- final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
- "Netconf is not configured, persister is not operational", true);
- final ConfigPusher configPusher = new ConfigPusher(address, nettyThreadGroup, maxWaitForCapabilitiesMillis,
- ConfigPusher.DEFAULT_CONNECTION_TIMEOUT_MILLIS);
+ final ConfigPusher configPusher = new ConfigPusher(getConfigurationForPusher(context, propertiesProvider));
// offload initialization to another thread in order to stop blocking activator
Runnable initializationRunnable = new Runnable() {
@@ -94,17 +98,59 @@ public class ConfigPersisterActivator implements BundleActivator {
logger.info("Configuration Persister initialization completed.");
}
};
- initializationThread = new Thread(initializationRunnable, "ConfigPersister-registrator");
+
+ initializationThread = initializationThreadFactory.newThread(initializationRunnable);
initializationThread.start();
}
+ private Pattern getIgnoredCapabilitiesProperty(PropertiesProviderBaseImpl propertiesProvider) {
+ String regexProperty = propertiesProvider.getProperty(IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX);
+ String regex;
+ if (regexProperty != null) {
+ regex = regexProperty;
+ } else {
+ regex = DEFAULT_IGNORED_REGEX;
+ }
+ return Pattern.compile(regex);
+ }
+
+ private Optional getMaxWaitForCapabilitiesProperty(PropertiesProviderBaseImpl propertiesProvider) {
+ String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS);
+ return Optional.fromNullable(timeoutProperty == null ? null : Long.valueOf(timeoutProperty));
+ }
+
+ private ConfigPusherConfiguration getConfigurationForPusher(BundleContext context,
+ PropertiesProviderBaseImpl propertiesProvider) {
+
+ // If configuration was injected via constructor, use it
+ if(initialConfigForPusher.isPresent())
+ return initialConfigForPusher.get();
+
+ Optional maxWaitForCapabilitiesMillis = getMaxWaitForCapabilitiesProperty(propertiesProvider);
+ final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
+ "Netconf is not configured, persister is not operational", true);
+
+ nettyThreadGroup = new NioEventLoopGroup();
+
+ ConfigPusherConfigurationBuilder configPusherConfigurationBuilder = ConfigPusherConfigurationBuilder.aConfigPusherConfiguration();
+
+ if(maxWaitForCapabilitiesMillis.isPresent())
+ configPusherConfigurationBuilder.withNetconfCapabilitiesWaitTimeoutMs(maxWaitForCapabilitiesMillis.get());
+
+ return configPusherConfigurationBuilder
+ .withEventLoopGroup(nettyThreadGroup)
+ .withNetconfAddress(address)
+ .build();
+ }
+
@Override
public void stop(BundleContext context) throws Exception {
initializationThread.interrupt();
if (jmxNotificationHandler != null) {
jmxNotificationHandler.close();
}
- nettyThreadGroup.shutdownGracefully();
+ if(nettyThreadGroup!=null)
+ nettyThreadGroup.shutdownGracefully();
persisterAggregator.close();
}
}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java
new file mode 100644
index 0000000000..230c74725d
--- /dev/null
+++ b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.persist.impl.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeoutException;
+
+import javax.management.MBeanServer;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.matchers.JUnitMatchers;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
+import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfiguration;
+import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfigurationBuilder;
+
+import com.google.common.collect.Lists;
+import io.netty.channel.nio.NioEventLoopGroup;
+
+public class ConfigPersisterTest {
+
+ private MockedBundleContext ctx;
+ private ConfigPersisterActivator configPersisterActivator;
+ private static final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+
+ private static final String NETCONF_ADDRESS = "localhost";
+ private static final String NETCONF_PORT = "18383";
+ private static NioEventLoopGroup eventLoopGroup;
+
+ private void setUpContextAndStartPersister(Thread.UncaughtExceptionHandler exHandler, String requiredCapability, ConfigPusherConfiguration configuration)
+ throws Exception {
+ MockedBundleContext.DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability;
+ ctx = new MockedBundleContext(NETCONF_ADDRESS, NETCONF_PORT);
+ configPersisterActivator = new ConfigPersisterActivator(getThreadFactory(exHandler), mBeanServer,
+ configuration);
+ configPersisterActivator.start(ctx.getBundleContext());
+ }
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ eventLoopGroup = new NioEventLoopGroup();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ configPersisterActivator.stop(ctx.getBundleContext());
+ }
+
+ @AfterClass
+ public static void closeNettyGroup() throws Exception {
+ eventLoopGroup.shutdownGracefully();
+ }
+
+ @Test
+ public void testPersisterNetconfNotStarting() throws Exception {
+ final TestingExceptionHandler handler = new TestingExceptionHandler();
+
+ setUpContextAndStartPersister(handler, "cap2", getConfiguration(100, 100).build());
+
+ waitTestToFinish(2000);
+
+ handler.assertException("connect to netconf endpoint", RuntimeException.class,
+ "Could not connect to netconf server");
+ }
+
+ @Test
+ public void testPersisterNotAllCapabilitiesProvided() throws Exception {
+ final TestingExceptionHandler handler = new TestingExceptionHandler();
+ ConfigPusherConfiguration cfg = getConfiguration(500, 1000)
+ .withNetconfCapabilitiesWaitTimeoutMs(1000).build();
+
+ setUpContextAndStartPersister(handler, "required-cap", cfg);
+
+ try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) {
+
+ waitTestToFinish(2500);
+
+ handler.assertException("retrieve required capabilities from netconf endpoint", RuntimeException.class,
+ "Expected but not found:[required-cap]");
+ }
+ }
+
+ @Test
+ public void testPersisterNoResponseFromNetconfAfterEdit() throws Exception {
+ final TestingExceptionHandler handler = new TestingExceptionHandler();
+ ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt();
+
+ setUpContextAndStartPersister(handler, "cap1", cfg);
+
+ try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) {
+
+ waitTestToFinish(3000);
+
+ handler.assertException("receive response from netconf endpoint", IllegalStateException.class,
+ "Unable to load", TimeoutException.class,
+ null, 3);
+
+ assertEquals(1 + 2, endpoint.getReceivedMessages().size());
+ assertHelloMessage(endpoint.getReceivedMessages().get(1));
+ assertEditMessage(endpoint.getReceivedMessages().get(2));
+ }
+ }
+
+ private ConfigPusherConfiguration getConfigurationWithOnePushAttempt() {
+ return getConfiguration(500, 1000)
+ .withNetconfCapabilitiesWaitTimeoutMs(1000)
+ .withNetconfPushConfigAttempts(1)
+ .withNetconfPushConfigDelayMs(100)
+ .withNetconfSendMessageMaxAttempts(3)
+ .withNetconfSendMessageDelayMs(500).build();
+ }
+
+ @Test
+ public void testPersisterSuccessfulPush() throws Exception {
+ final TestingExceptionHandler handler = new TestingExceptionHandler();
+ ConfigPusherConfiguration cfg = getConfigurationForSuccess();
+
+ setUpContextAndStartPersister(handler, "cap1", cfg);
+
+ try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
+ MockNetconfEndpoint.okMessage)) {
+
+ waitTestToFinish(4000);
+
+ handler.assertException("register as JMX listener", RuntimeException.class,
+ "Cannot register as JMX listener to netconf");
+
+ assertEquals(1 + 3, endpoint.getReceivedMessages().size());
+ assertCommitMessage(endpoint.getReceivedMessages().get(3));
+ }
+ }
+
+ private ConfigPusherConfiguration getConfigurationForSuccess() {
+ return getConfiguration(500, 1000)
+ .withNetconfCapabilitiesWaitTimeoutMs(1000)
+ .withNetconfPushConfigAttempts(3)
+ .withNetconfPushConfigDelayMs(100)
+ .withNetconfSendMessageMaxAttempts(3)
+ .withNetconfSendMessageDelayMs(500).build();
+ }
+
+ @Test
+ public void testPersisterConflictingVersionException() throws Exception {
+ final TestingExceptionHandler handler = new TestingExceptionHandler();
+ ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt();
+
+ setUpContextAndStartPersister(handler, "cap1", cfg);
+
+ try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
+ MockNetconfEndpoint.conflictingVersionErrorMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier();) {
+
+ Thread.sleep(4000);
+
+ handler.assertException("register as JMX listener", IllegalStateException.class,
+ "Maximum attempt count has been reached for pushing", ConflictingVersionException.class, "Optimistic lock failed", 1);
+
+ assertEquals(1 + 3, endpoint.getReceivedMessages().size());
+ assertCommitMessage(endpoint.getReceivedMessages().get(3));
+ }
+ }
+
+ @Test
+ public void testPersisterConflictingVersionExceptionThenSuccess() throws Exception {
+ final TestingExceptionHandler handler = new TestingExceptionHandler();
+ ConfigPusherConfiguration cfg = getConfigurationForSuccess();
+
+ setUpContextAndStartPersister(handler, "cap1", cfg);
+
+ MockNetconfEndpoint.MessageSequence conflictingMessageSequence = new MockNetconfEndpoint.MessageSequence(
+ MockNetconfEndpoint.okMessage, MockNetconfEndpoint.conflictingVersionErrorMessage);
+ MockNetconfEndpoint.MessageSequence okMessageSequence = new MockNetconfEndpoint.MessageSequence(
+ MockNetconfEndpoint.okMessage, MockNetconfEndpoint.okMessage);
+
+ try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1",
+ Lists.newArrayList(conflictingMessageSequence, okMessageSequence));
+ DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
+
+ Thread.sleep(4000);
+
+ handler.assertNoException();
+
+ assertEquals(1 + 3/*Hello + Edit + Commit*/ + 3/*Hello + Edit + Commit*/, endpoint.getReceivedMessages().size());
+ assertCommitMessage(endpoint.getReceivedMessages().get(6));
+ }
+ }
+
+ @Test
+ public void testPersisterSuccessfulPushAndSuccessfulJMXRegistration() throws Exception {
+ final TestingExceptionHandler handler = new TestingExceptionHandler();
+ ConfigPusherConfiguration cfg = getConfigurationForSuccess();
+
+ setUpContextAndStartPersister(handler, "cap1", cfg);
+
+ try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
+ MockNetconfEndpoint.okMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
+
+ Thread.sleep(2000);
+
+ handler.assertNoException();
+
+ assertEquals(1 + 3, endpoint.getReceivedMessages().size());
+ }
+ }
+
+ private ConfigPusherConfigurationBuilder getConfiguration(int connectionAttemptDelayMs, int connectionAttemptTimeoutMs) {
+ return ConfigPusherConfigurationBuilder.aConfigPusherConfiguration()
+ .withEventLoopGroup(eventLoopGroup)
+ .withConnectionAttemptDelayMs(connectionAttemptDelayMs)
+ .withConnectionAttemptTimeoutMs(connectionAttemptTimeoutMs)
+ .withNetconfCapabilitiesWaitTimeoutMs(44)
+ .withNetconfAddress(new InetSocketAddress(NETCONF_ADDRESS, Integer.valueOf(NETCONF_PORT)));
+ }
+
+ private void waitTestToFinish(int i) throws InterruptedException {
+ Thread.sleep(i);
+ }
+
+
+ private DefaultCommitNotificationProducer startJMXCommitNotifier() {
+ return new DefaultCommitNotificationProducer(mBeanServer);
+ }
+
+ private void assertEditMessage(String netconfMessage) {
+ assertThat(netconfMessage,
+ JUnitMatchers.containsString(MockedBundleContext.DummyAdapterWithInitialSnapshot.CONFIG_SNAPSHOT));
+ }
+
+ private void assertCommitMessage(String netconfMessage) {
+ assertThat(netconfMessage, JUnitMatchers.containsString(""));
+ assertThat(netconfMessage, JUnitMatchers.containsString(""));
+ }
+
+ private MockNetconfEndpoint startMockNetconfEndpoint(String capability, List messageSequences) {
+ // Add first empty sequence for testing connection created by config persister at startup
+ messageSequences.add(0, new MockNetconfEndpoint.MessageSequence(Collections.emptyList()));
+ return new MockNetconfEndpoint(capability, NETCONF_PORT, messageSequences);
+ }
+
+ private MockNetconfEndpoint startMockNetconfEndpoint(String capability, String... messages) {
+ return startMockNetconfEndpoint(capability, Lists.newArrayList(new MockNetconfEndpoint.MessageSequence(messages)));
+ }
+
+ public ThreadFactory getThreadFactory(final Thread.UncaughtExceptionHandler exHandler) {
+ return new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread thread = new Thread(r, "config-persister-testing-activator");
+ thread.setUncaughtExceptionHandler(exHandler);
+ return thread;
+ }
+ };
+ }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java
new file mode 100644
index 0000000000..913db280b5
--- /dev/null
+++ b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.persist.impl.osgi;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+
+import com.google.common.collect.Lists;
+
+class MockNetconfEndpoint implements AutoCloseable {
+
+ public static final int READ_SOCKET_TIMEOUT = 3000;
+
+ public static final String MSG_SEPARATOR = "]]>]]>\n";
+
+ private final AtomicBoolean stopped = new AtomicBoolean(false);
+ private List receivedMessages = Lists.newCopyOnWriteArrayList();
+ private Thread innerThread;
+
+ MockNetconfEndpoint(String capability, String netconfPort, List messageSequence) {
+ helloMessage = helloMessage.replace("capability_place_holder", capability);
+ start(netconfPort, messageSequence);
+ }
+
+ private String helloMessage = "\n" +
+ "\n" +
+ "capability_place_holder\n" +
+ "\n" +
+ "1\n" +
+ "\n" +
+ MSG_SEPARATOR;
+
+ public static String conflictingVersionErrorMessage;
+ static {
+ try {
+ conflictingVersionErrorMessage = XmlUtil.toString(XmlFileLoader
+ .xmlFileToDocument("netconfMessages/conflictingversion/conflictingVersionResponse.xml")) + MSG_SEPARATOR;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static String okMessage = "\n" +
+ "\n" +
+ "" +
+ MSG_SEPARATOR ;
+
+ private void start(final String port, final List messagesToSend) {
+ innerThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ int clientCounter = 0;
+
+ while (stopped.get() == false) {
+ try (ServerSocket s = new ServerSocket(Integer.valueOf(port))) {
+ s.setSoTimeout(READ_SOCKET_TIMEOUT);
+
+ Socket clientSocket = s.accept();
+ clientCounter++;
+ clientSocket.setSoTimeout(READ_SOCKET_TIMEOUT);
+
+ PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
+ BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+
+ // Negotiate
+ sendMessage(out, helloMessage);
+ receiveMessage(in);
+
+ // Accept next message (edit-config)
+ receiveMessage(in);
+
+ for (String message : getMessageSequenceForClient(messagesToSend, clientCounter)) {
+ sendMessage(out, message);
+ receiveMessage(in);
+ }
+ } catch (SocketTimeoutException e) {
+ // No more activity on netconf endpoint, close
+ return;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private Iterable extends String> getMessageSequenceForClient(List messagesToSend,
+ int clientCounter) {
+ if (messagesToSend.size() <= clientCounter) {
+ return messagesToSend.get(messagesToSend.size() - 1).getMessages();
+ } else {
+ return messagesToSend.get(clientCounter - 1).getMessages();
+ }
+ }
+
+ private void receiveMessage(BufferedReader in) throws Exception {
+ String message = readMessage(in);
+ if(message == null || message.equals(""))
+ return;
+ receivedMessages.add(message);
+ }
+
+ private String readMessage(BufferedReader in) throws IOException {
+ int c;
+ StringBuilder b = new StringBuilder();
+
+ while((c = in.read()) != -1) {
+ b.append((char)c);
+ if(b.toString().endsWith("]]>]]>"))
+ break;
+ }
+
+ return b.toString();
+ }
+
+ private void sendMessage(PrintWriter out, String message) throws InterruptedException {
+ out.print(message);
+ out.flush();
+ }
+
+ });
+ innerThread.setName("Mocked-netconf-endpoint-inner-thread");
+ innerThread.start();
+ }
+
+ public List getReceivedMessages() {
+ return receivedMessages;
+ }
+
+ public void close() throws IOException, InterruptedException {
+ stopped.set(true);
+ innerThread.join();
+ }
+
+ static class MessageSequence {
+ private List messages;
+
+ MessageSequence(List messages) {
+ this.messages = messages;
+ }
+
+ MessageSequence(String... messages) {
+ this(Lists.newArrayList(messages));
+ }
+
+ public Collection getMessages() {
+ return messages;
+ }
+ }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java
new file mode 100644
index 0000000000..97cf7ecfe7
--- /dev/null
+++ b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.persist.impl.osgi;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.config.persist.api.PropertiesProvider;
+import org.opendaylight.controller.netconf.persist.impl.DummyAdapter;
+import org.osgi.framework.BundleContext;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import static org.mockito.Mockito.doReturn;
+
+final class MockedBundleContext {
+
+ @Mock
+ private BundleContext context;
+
+ MockedBundleContext(String netconfAddress, String netconfPort) {
+ MockitoAnnotations.initMocks(this);
+ initContext(netconfAddress, netconfPort);
+ }
+
+ public BundleContext getBundleContext() {
+ return context;
+ }
+
+ private void initContext(String netconfAddress, String netconfPort) {
+ initProp(context, ConfigPersisterActivator.IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX, null);
+
+ initPropNoPrefix(context, "netconf.tcp.client.address", netconfAddress);
+ initPropNoPrefix(context, "netconf.tcp.client.port", netconfPort);
+
+ initProp(context, "active", "1");
+ initProp(context, "1." + ConfigPersisterActivator.STORAGE_ADAPTER_CLASS_PROP_SUFFIX, DummyAdapterWithInitialSnapshot.class.getName());
+ initProp(context, "1." + "readonly", "false");
+ initProp(context, "1." + ".properties.fileStorage", "target/configuration-persister-test/initial/");
+
+ }
+
+ private void initProp(BundleContext context, String key, String value) {
+ initPropNoPrefix(context, ConfigPersisterActivator.NETCONF_CONFIG_PERSISTER + "." + key, value);
+ }
+
+ private void initPropNoPrefix(BundleContext context, String key, String value) {
+ doReturn(value).when(context).getProperty(key);
+ }
+
+ public static class DummyAdapterWithInitialSnapshot extends DummyAdapter {
+
+ public static final String CONFIG_SNAPSHOT = "config-snapshot";
+ public static String expectedCapability = "cap2";
+
+ @Override
+ public List loadLastConfigs() throws IOException {
+ return Lists.newArrayList(getConfigSnapshopt());
+ }
+
+ @Override
+ public Persister instantiate(PropertiesProvider propertiesProvider) {
+ return this;
+ }
+
+ public ConfigSnapshotHolder getConfigSnapshopt() {
+ return new ConfigSnapshotHolder() {
+ @Override
+ public String getConfigSnapshot() {
+ return "<" + CONFIG_SNAPSHOT + "/>";
+ }
+
+ @Override
+ public SortedSet getCapabilities() {
+ TreeSet strings = Sets.newTreeSet();
+ strings.add(expectedCapability);
+ return strings;
+ }
+
+ @Override
+ public String toString() {
+ return getConfigSnapshot();
+ }
+ };
+ }
+ }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java
new file mode 100644
index 0000000000..d42c15b834
--- /dev/null
+++ b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.persist.impl.osgi;
+
+import org.junit.matchers.JUnitMatchers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+final class TestingExceptionHandler implements Thread.UncaughtExceptionHandler {
+
+ private Throwable t;
+
+ @Override
+ public void uncaughtException(Thread t, Throwable e) {
+ this.t = e;
+ }
+
+ public void assertException(String failMessageSuffix, Class extends Exception> exType, String exMessageToContain) {
+ if(t == null) {
+ fail("Should fail to " + failMessageSuffix);
+ }
+ else {
+ assertException(t, exType, exMessageToContain);
+ }
+ }
+
+ public void assertNoException() {
+ assertNull("No exception expected but was " + t, t);
+ }
+
+ private void assertException(Throwable t, Class extends Exception> exType, String exMessageToContain) {
+ assertEquals("Expected exception of type " + exType + " but was " + t, exType, t.getClass());
+ if(exMessageToContain!=null) {
+ assertThat(t.getMessage(), JUnitMatchers.containsString(exMessageToContain));
+ }
+ }
+
+ public void assertException(String failMessageSuffix, Class extends Exception> exType,
+ String exMessageToContain, Class extends Exception> nestedExType, String nestedExMessageToContain,
+ int nestedExDepth) {
+ assertException(failMessageSuffix, exType, exMessageToContain);
+ assertNotNull("Expected nested exception in " + t, t.getCause());
+ assertException(getNestedException(t, nestedExDepth), nestedExType, nestedExMessageToContain);
+ }
+
+ private Throwable getNestedException(Throwable t, int nestedExDepth) {
+
+ int depth = 0;
+ while(t.getCause() != null) {
+ t = t.getCause();
+ depth++;
+ if(nestedExDepth == depth)
+ return t;
+ }
+ throw new IllegalArgumentException("Unable to get nested exception from " + t + " from depth " + nestedExDepth);
+ }
+}
diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/test/XmlFileLoader.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/test/XmlFileLoader.java
index 28cb4d8194..457dda3080 100644
--- a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/test/XmlFileLoader.java
+++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/test/XmlFileLoader.java
@@ -45,7 +45,7 @@ public class XmlFileLoader {
public static Document xmlFileToDocument(final String fileName) throws IOException, SAXException,
ParserConfigurationException {
try (InputStream resourceAsStream = XmlFileLoader.class.getClassLoader().getResourceAsStream(fileName)) {
- Preconditions.checkNotNull(resourceAsStream);
+ Preconditions.checkNotNull(resourceAsStream, fileName);
final Document doc = XmlUtil.readXmlToDocument(resourceAsStream);
return doc;
}
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java
index 680b028f9a..f93191220b 100644
--- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java
+++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java
@@ -37,12 +37,15 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;
import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.sal.utils.ServiceHelper;
/**
- * Open DOVE Northbound REST APIs.
- * This class provides REST APIs for managing the open DOVE
+ * Neutron Northbound REST APIs.
+ * This class provides REST APIs for managing Neutron Floating IPs
*
*
*
@@ -139,7 +142,7 @@ public class NeutronFloatingIPsNorthbound {
+ RestMessages.SERVICEUNAVAILABLE.toString());
}
if (!floatingIPInterface.floatingIPExists(floatingipUUID))
- return Response.status(404).build();
+ throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
if (fields.size() > 0) {
NeutronFloatingIP ans = floatingIPInterface.getFloatingIP(floatingipUUID);
return Response.status(200).entity(
@@ -187,42 +190,42 @@ public class NeutronFloatingIPsNorthbound {
NeutronFloatingIP singleton = input.getSingleton();
// check existence of id in cache and return badrequest if exists
if (floatingIPInterface.floatingIPExists(singleton.getID()))
- return Response.status(400).build();
+ throw new BadRequestException("Floating IP UUID already exists.");
// check if the external network is specified, exists, and is an external network
String externalNetworkUUID = singleton.getFloatingNetworkUUID();
if (externalNetworkUUID == null)
- return Response.status(400).build();
+ throw new BadRequestException("external network UUID doesn't exist.");
if (!networkInterface.networkExists(externalNetworkUUID))
- return Response.status(400).build();
+ throw new BadRequestException("external network UUID doesn't exist.");
NeutronNetwork externNetwork = networkInterface.getNetwork(externalNetworkUUID);
if (!externNetwork.isRouterExternal())
- return Response.status(400).build();
+ throw new BadRequestException("external network isn't marked router:external");
// 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)
- return Response.status(400).build();
+ throw new BadRequestException("external network doesn't have a subnet");
NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
if (!externSubnet.isValidIP(floatingIP))
- return Response.status(400).build();
+ throw new BadRequestException("external IP isn't valid for the specified subnet.");
if (externSubnet.isIPInUse(floatingIP))
- return Response.status(409).build();
+ throw new ResourceConflictException("floating IP is in use.");
}
// if port_id is specified, then check that the port exists and has at least one IP
String port_id = singleton.getPortUUID();
if (port_id != null) {
String fixedIP = null; // used for the fixedIP calculation
if (!portInterface.portExists(port_id))
- return Response.status(404).build();
+ throw new ResourceNotFoundException("Port UUID doesn't exist.");
NeutronPort port = portInterface.getPort(port_id);
if (port.getFixedIPs().size() < 1)
- return Response.status(400).build();
+ throw new BadRequestException("port UUID doesn't have an IP address.");
// if there is more than one fixed IP then check for fixed_ip_address
// and that it is in the list of port addresses
if (port.getFixedIPs().size() > 1) {
fixedIP = singleton.getFixedIPAddress();
if (fixedIP == null)
- return Response.status(400).build();
+ throw new BadRequestException("fixed IP address doesn't exist.");
Iterator i = port.getFixedIPs().iterator();
boolean validFixedIP = false;
while (i.hasNext() && !validFixedIP) {
@@ -231,15 +234,15 @@ public class NeutronFloatingIPsNorthbound {
validFixedIP = true;
}
if (!validFixedIP)
- return Response.status(400).build();
+ throw new BadRequestException("can't find a valid fixed IP address");
} else {
fixedIP = port.getFixedIPs().get(0).getIpAddress();
if (singleton.getFixedIPAddress() != null && !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
- return Response.status(400).build();
+ throw new BadRequestException("mismatched fixed IP address in request");
}
//lastly check that this fixed IP address isn't already used
if (port.isBoundToFloatingIP(fixedIP))
- return Response.status(409).build();
+ throw new ResourceConflictException("fixed IP is in use.");
singleton.setFixedIPAddress(fixedIP);
}
Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null);
@@ -259,7 +262,7 @@ public class NeutronFloatingIPsNorthbound {
}
}
} else {
- return Response.status(400).build();
+ throw new BadRequestException("only singleton requests allowed.");
}
return Response.status(201).entity(input).build();
}
@@ -303,14 +306,14 @@ public class NeutronFloatingIPsNorthbound {
+ RestMessages.SERVICEUNAVAILABLE.toString());
}
if (!floatingIPInterface.floatingIPExists(floatingipUUID))
- return Response.status(404).build();
+ throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
NeutronFloatingIP sourceFloatingIP = floatingIPInterface.getFloatingIP(floatingipUUID);
if (!input.isSingleton())
- return Response.status(400).build();
+ throw new BadRequestException("only singleton requests allowed.");
NeutronFloatingIP singleton = input.getSingleton();
if (singleton.getID() != null)
- return Response.status(400).build();
+ throw new BadRequestException("singleton UUID doesn't exist.");
NeutronNetwork externNetwork = networkInterface.getNetwork(
sourceFloatingIP.getFloatingNetworkUUID());
@@ -319,12 +322,12 @@ public class NeutronFloatingIPsNorthbound {
String floatingIP = singleton.getFloatingIPAddress();
if (floatingIP != null) {
if (externNetwork.getSubnets().size() > 1)
- return Response.status(400).build();
+ throw new BadRequestException("external network doesn't have a subnet.");
NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
if (!externSubnet.isValidIP(floatingIP))
- return Response.status(400).build();
+ throw new BadRequestException("floating IP not valid for external subnet");
if (externSubnet.isIPInUse(floatingIP))
- return Response.status(409).build();
+ throw new ResourceConflictException("floating IP is in use.");
}
// if port_id is specified, then check that the port exists and has at least one IP
@@ -332,16 +335,16 @@ public class NeutronFloatingIPsNorthbound {
if (port_id != null) {
String fixedIP = null; // used for the fixedIP calculation
if (!portInterface.portExists(port_id))
- return Response.status(404).build();
+ throw new ResourceNotFoundException("Port UUID doesn't exist.");
NeutronPort port = portInterface.getPort(port_id);
if (port.getFixedIPs().size() < 1)
- return Response.status(400).build();
+ throw new BadRequestException("port ID doesn't have a fixed IP address.");
// if there is more than one fixed IP then check for fixed_ip_address
// and that it is in the list of port addresses
if (port.getFixedIPs().size() > 1) {
fixedIP = singleton.getFixedIPAddress();
if (fixedIP == null)
- return Response.status(400).build();
+ throw new BadRequestException("request doesn't have a fixed IP address");
Iterator i = port.getFixedIPs().iterator();
boolean validFixedIP = false;
while (i.hasNext() && !validFixedIP) {
@@ -350,16 +353,16 @@ public class NeutronFloatingIPsNorthbound {
validFixedIP = true;
}
if (!validFixedIP)
- return Response.status(400).build();
+ throw new BadRequestException("couldn't find a valid fixed IP address");
} else {
fixedIP = port.getFixedIPs().get(0).getIpAddress();
if (singleton.getFixedIPAddress() != null &&
!fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
- return Response.status(400).build();
+ throw new BadRequestException("mismatch in fixed IP addresses");
}
//lastly check that this fixed IP address isn't already used
if (port.isBoundToFloatingIP(fixedIP))
- return Response.status(409).build();
+ throw new ResourceConflictException("fixed IP is in use.");
singleton.setFixedIPAddress(fixedIP);
}
NeutronFloatingIP target = floatingIPInterface.getFloatingIP(floatingipUUID);
@@ -403,7 +406,7 @@ public class NeutronFloatingIPsNorthbound {
+ RestMessages.SERVICEUNAVAILABLE.toString());
}
if (!floatingIPInterface.floatingIPExists(floatingipUUID))
- return Response.status(404).build();
+ throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
// TODO: need to undo port association if it exists
NeutronFloatingIP singleton = floatingIPInterface.getFloatingIP(floatingipUUID);
Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null);
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java
index c08ee80e24..d7437c831d 100644
--- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java
+++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java
@@ -33,12 +33,15 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.sal.utils.ServiceHelper;
/**
- * Open DOVE Northbound REST APIs for Network.
- * This class provides REST APIs for managing open DOVE internals related to Networks
+ * Neutron Northbound REST APIs for Network.
+ * This class provides REST APIs for managing neutron Networks
*
*
*
@@ -154,7 +157,7 @@ public class NeutronNetworksNorthbound {
+ RestMessages.SERVICEUNAVAILABLE.toString());
}
if (!networkInterface.networkExists(netUUID)) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("network UUID does not exist.");
}
if (fields.size() > 0) {
NeutronNetwork ans = networkInterface.getNetwork(netUUID);
@@ -189,7 +192,7 @@ public class NeutronNetworksNorthbound {
* network ID can't already exist
*/
if (networkInterface.networkExists(singleton.getID())) {
- return Response.status(400).build();
+ throw new BadRequestException("network UUID already exists");
}
Object[] instances = ServiceHelper.getGlobalInstances(INeutronNetworkAware.class, this, null);
@@ -226,10 +229,10 @@ public class NeutronNetworksNorthbound {
* already in this bulk request
*/
if (networkInterface.networkExists(test.getID())) {
- return Response.status(400).build();
+ throw new BadRequestException("network UUID already exists");
}
if (testMap.containsKey(test.getID())) {
- return Response.status(400).build();
+ throw new BadRequestException("network UUID already exists");
}
if (instances != null) {
for (Object instance: instances) {
@@ -285,10 +288,10 @@ public class NeutronNetworksNorthbound {
* network has to exist and only a single delta is supported
*/
if (!networkInterface.networkExists(netUUID)) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("network UUID does not exist.");
}
if (!input.isSingleton()) {
- return Response.status(400).build();
+ throw new BadRequestException("only singleton edits supported");
}
NeutronNetwork delta = input.getSingleton();
@@ -297,7 +300,7 @@ public class NeutronNetworksNorthbound {
*/
if (delta.getID() != null || delta.getTenantID() != null ||
delta.getStatus() != null) {
- return Response.status(400).build();
+ throw new BadRequestException("attribute edit blocked by Neutron");
}
Object[] instances = ServiceHelper.getGlobalInstances(INeutronNetworkAware.class, this, null);
@@ -347,10 +350,10 @@ public class NeutronNetworksNorthbound {
* network has to exist and not be in use before it can be removed
*/
if (!networkInterface.networkExists(netUUID)) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("network UUID does not exist.");
}
if (networkInterface.networkInUse(netUUID)) {
- return Response.status(409).build();
+ throw new ResourceConflictException("Network ID in use");
}
NeutronNetwork singleton = networkInterface.getNetwork(netUUID);
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java
index c26e0229d0..9f24e79ea0 100644
--- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java
+++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java
@@ -36,12 +36,15 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;
import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.sal.utils.ServiceHelper;
/**
- * Open DOVE Northbound REST APIs.
- * This class provides REST APIs for managing the open DOVE
+ * Neutron Northbound REST APIs.
+ * This class provides REST APIs for managing neutron port objects
*
*
*
@@ -148,7 +151,7 @@ public class NeutronPortsNorthbound {
+ RestMessages.SERVICEUNAVAILABLE.toString());
}
if (!portInterface.portExists(portUUID)) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("port UUID does not exist.");
}
if (fields.size() > 0) {
NeutronPort ans = portInterface.getPort(portUUID);
@@ -200,20 +203,20 @@ public class NeutronPortsNorthbound {
* have a valid MAC and the MAC not be in use
*/
if (singleton.getNetworkUUID() == null) {
- return Response.status(400).build();
+ throw new BadRequestException("network UUID musy be specified");
}
if (portInterface.portExists(singleton.getID())) {
- return Response.status(400).build();
+ throw new BadRequestException("port UUID already exists");
}
if (!networkInterface.networkExists(singleton.getNetworkUUID())) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("network UUID does not exist.");
}
if (singleton.getMacAddress() == null ||
!singleton.getMacAddress().matches(mac_regex)) {
- return Response.status(400).build();
+ throw new BadRequestException("MAC address not properly formatted");
}
if (portInterface.macInUse(singleton.getMacAddress())) {
- return Response.status(409).build();
+ throw new ResourceConflictException("MAC Address is in use.");
}
Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
if (instances != null) {
@@ -237,21 +240,21 @@ public class NeutronPortsNorthbound {
while (fixedIPIterator.hasNext()) {
Neutron_IPs ip = fixedIPIterator.next();
if (ip.getSubnetUUID() == null) {
- return Response.status(400).build();
+ throw new BadRequestException("subnet UUID not specified");
}
if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
- return Response.status(400).build();
+ throw new BadRequestException("subnet UUID must exists");
}
NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
if (!singleton.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
- return Response.status(400).build();
+ throw new BadRequestException("network UUID must match that of subnet");
}
if (ip.getIpAddress() != null) {
if (!subnet.isValidIP(ip.getIpAddress())) {
- return Response.status(400).build();
+ throw new BadRequestException("IP address is not valid");
}
if (subnet.isIPInUse(ip.getIpAddress())) {
- return Response.status(409).build();
+ throw new ResourceConflictException("IP address is in use.");
}
}
}
@@ -279,32 +282,32 @@ public class NeutronPortsNorthbound {
* can't already contain a new port with the same UUID
*/
if (portInterface.portExists(test.getID())) {
- return Response.status(400).build();
+ throw new BadRequestException("port UUID already exists");
}
if (testMap.containsKey(test.getID())) {
- return Response.status(400).build();
+ throw new BadRequestException("port UUID already exists");
}
for (NeutronPort check : testMap.values()) {
if (test.getMacAddress().equalsIgnoreCase(check.getMacAddress())) {
- return Response.status(409).build();
+ throw new ResourceConflictException("MAC address already allocated");
}
for (Neutron_IPs test_fixedIP : test.getFixedIPs()) {
for (Neutron_IPs check_fixedIP : check.getFixedIPs()) {
if (test_fixedIP.getIpAddress().equals(check_fixedIP.getIpAddress())) {
- return Response.status(409).build();
+ throw new ResourceConflictException("IP address already allocated");
}
}
}
}
testMap.put(test.getID(), test);
if (!networkInterface.networkExists(test.getNetworkUUID())) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("network UUID does not exist.");
}
if (!test.getMacAddress().matches(mac_regex)) {
- return Response.status(400).build();
+ throw new BadRequestException("MAC address not properly formatted");
}
if (portInterface.macInUse(test.getMacAddress())) {
- return Response.status(409).build();
+ throw new ResourceConflictException("MAC address in use");
}
if (instances != null) {
for (Object instance : instances) {
@@ -327,23 +330,23 @@ public class NeutronPortsNorthbound {
while (fixedIPIterator.hasNext()) {
Neutron_IPs ip = fixedIPIterator.next();
if (ip.getSubnetUUID() == null) {
- return Response.status(400).build();
+ throw new BadRequestException("subnet UUID must be specified");
}
if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
- return Response.status(400).build();
+ throw new BadRequestException("subnet UUID doesn't exists");
}
NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
if (!test.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
- return Response.status(400).build();
+ throw new BadRequestException("network UUID must match that of subnet");
}
if (ip.getIpAddress() != null) {
if (!subnet.isValidIP(ip.getIpAddress())) {
- return Response.status(400).build();
+ throw new BadRequestException("ip address not valid");
}
//TODO: need to add consideration for a fixed IP being assigned the same address as a allocated IP in the
//same bulk create
if (subnet.isIPInUse(ip.getIpAddress())) {
- return Response.status(409).build();
+ throw new ResourceConflictException("IP address in use");
}
}
}
@@ -399,11 +402,11 @@ public class NeutronPortsNorthbound {
// port has to exist and only a single delta is supported
if (!portInterface.portExists(portUUID)) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("port UUID does not exist.");
}
NeutronPort target = portInterface.getPort(portUUID);
if (!input.isSingleton()) {
- return Response.status(400).build();
+ throw new BadRequestException("only singleton edit suported");
}
NeutronPort singleton = input.getSingleton();
NeutronPort original = portInterface.getPort(portUUID);
@@ -411,7 +414,7 @@ public class NeutronPortsNorthbound {
// deltas restricted by Neutron
if (singleton.getID() != null || singleton.getTenantID() != null ||
singleton.getStatus() != null) {
- return Response.status(400).build();
+ throw new BadRequestException("attribute change blocked by Neutron");
}
Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
@@ -432,21 +435,21 @@ public class NeutronPortsNorthbound {
while (fixedIPIterator.hasNext()) {
Neutron_IPs ip = fixedIPIterator.next();
if (ip.getSubnetUUID() == null) {
- return Response.status(400).build();
+ throw new BadRequestException("subnet UUID must be specified");
}
if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
- return Response.status(400).build();
+ throw new BadRequestException("subnet UUID doesn't exist.");
}
NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
if (!target.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
- return Response.status(400).build();
+ throw new BadRequestException("network UUID must match that of subnet");
}
if (ip.getIpAddress() != null) {
if (!subnet.isValidIP(ip.getIpAddress())) {
- return Response.status(400).build();
+ throw new BadRequestException("invalid IP address");
}
if (subnet.isIPInUse(ip.getIpAddress())) {
- return Response.status(409).build();
+ throw new ResourceConflictException("IP address in use");
}
}
}
@@ -454,7 +457,7 @@ public class NeutronPortsNorthbound {
// TODO: Support change of security groups
// update the port and return the modified object
- portInterface.updatePort(portUUID, singleton);
+ portInterface.updatePort(portUUID, singleton);
NeutronPort updatedPort = portInterface.getPort(portUUID);
if (instances != null) {
for (Object instance : instances) {
@@ -488,7 +491,7 @@ public class NeutronPortsNorthbound {
// port has to exist and not be owned by anyone. then it can be removed from the cache
if (!portInterface.portExists(portUUID)) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("port UUID does not exist.");
}
NeutronPort port = portInterface.getPort(portUUID);
if (port.getDeviceID() != null ||
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java
index fc7e0f7efb..17b2fcfcf9 100644
--- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java
+++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java
@@ -37,13 +37,16 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronRouter;
import org.opendaylight.controller.networkconfig.neutron.NeutronRouter_Interface;
import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.sal.utils.ServiceHelper;
/**
- * Open DOVE Northbound REST APIs.
- * This class provides REST APIs for managing the open DOVE
+ * Neutron Northbound REST APIs.
+ * This class provides REST APIs for managing neutron routers
*
*
*
@@ -141,8 +144,9 @@ public class NeutronRoutersNorthbound {
throw new ServiceUnavailableException("Router CRUD Interface "
+ RestMessages.SERVICEUNAVAILABLE.toString());
}
- if (!routerInterface.routerExists(routerUUID))
- return Response.status(404).build();
+ if (!routerInterface.routerExists(routerUUID)) {
+ throw new ResourceNotFoundException("Router UUID not found");
+ }
if (fields.size() > 0) {
NeutronRouter ans = routerInterface.getRouter(routerUUID);
return Response.status(200).entity(
@@ -184,14 +188,14 @@ public class NeutronRoutersNorthbound {
* exists and has been designated as "router:external"
*/
if (routerInterface.routerExists(singleton.getID()))
- return Response.status(400).build();
+ throw new BadRequestException("router UUID already exists");
if (singleton.getExternalGatewayInfo() != null) {
String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
if (!networkInterface.networkExists(externNetworkPtr))
- return Response.status(400).build();
+ throw new BadRequestException("External Network Pointer doesn't exist");
NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
if (!externNetwork.isRouterExternal())
- return Response.status(400).build();
+ throw new BadRequestException("External Network Pointer isn't marked as router:external");
}
Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
if (instances != null) {
@@ -218,7 +222,7 @@ public class NeutronRoutersNorthbound {
/*
* only singleton router creates supported
*/
- return Response.status(400).build();
+ throw new BadRequestException("Only singleton router creates supported");
}
return Response.status(201).entity(input).build();
}
@@ -256,9 +260,9 @@ public class NeutronRoutersNorthbound {
* router has to exist and only a single delta can be supplied
*/
if (!routerInterface.routerExists(routerUUID))
- return Response.status(404).build();
+ throw new ResourceNotFoundException("Router UUID not found");
if (!input.isSingleton())
- return Response.status(400).build();
+ throw new BadRequestException("Only single router deltas supported");
NeutronRouter singleton = input.getSingleton();
NeutronRouter original = routerInterface.getRouter(routerUUID);
@@ -267,7 +271,7 @@ public class NeutronRoutersNorthbound {
*/
if (singleton.getID() != null || singleton.getTenantID() != null ||
singleton.getStatus() != null)
- return Response.status(400).build();
+ throw new BadRequestException("Request attribute change not allowed");
Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
if (instances != null) {
@@ -285,10 +289,10 @@ public class NeutronRoutersNorthbound {
if (singleton.getExternalGatewayInfo() != null) {
String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
if (!networkInterface.networkExists(externNetworkPtr))
- return Response.status(400).build();
+ throw new BadRequestException("External Network Pointer does not exist");
NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
if (!externNetwork.isRouterExternal())
- return Response.status(400).build();
+ throw new BadRequestException("External Network Pointer isn't marked as router:external");
}
/*
@@ -330,9 +334,9 @@ public class NeutronRoutersNorthbound {
* verify that the router exists and is not in use before removing it
*/
if (!routerInterface.routerExists(routerUUID))
- return Response.status(404).build();
+ throw new ResourceNotFoundException("Router UUID not found");
if (routerInterface.routerInUse(routerUUID))
- return Response.status(409).build();
+ throw new ResourceConflictException("Router UUID in Use");
NeutronRouter singleton = routerInterface.getRouter(routerUUID);
Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
if (instances != null) {
@@ -393,28 +397,27 @@ public class NeutronRoutersNorthbound {
* or a port id, but not both, this code assumes that the plugin has filled everything in for us and so both must be present
*/
if (!routerInterface.routerExists(routerUUID))
- return Response.status(400).build();
+ throw new BadRequestException("Router UUID doesn't exist");
NeutronRouter target = routerInterface.getRouter(routerUUID);
if (input.getSubnetUUID() == null ||
input.getPortUUID() == null)
- return Response.status(400).build();
+ throw new BadRequestException("Must specify at subnet id, port id or both");
// check that the port is part of the subnet
NeutronSubnet targetSubnet = subnetInterface.getSubnet(input.getSubnetUUID());
if (targetSubnet == null)
- return Response.status(400).build();
+ throw new BadRequestException("Subnet id doesn't exist");
NeutronPort targetPort = portInterface.getPort(input.getPortUUID());
if (targetPort == null)
- return Response.status(400).build();
+ throw new BadRequestException("Port id doesn't exist");
if (!targetSubnet.getPortsInSubnet().contains(targetPort))
- return Response.status(400).build();
+ throw new BadRequestException("Port id not part of subnet id");
if (targetPort.getFixedIPs().size() != 1)
- return Response.status(400).build();
+ throw new BadRequestException("Port id must have a single fixedIP address");
if (targetPort.getDeviceID() != null ||
targetPort.getDeviceOwner() != null)
- return Response.status(409).build();
-
+ throw new ResourceConflictException("Target Port already allocated");
Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
if (instances != null) {
for (Object instance : instances) {
@@ -475,7 +478,7 @@ public class NeutronRoutersNorthbound {
// verify the router exists
if (!routerInterface.routerExists(routerUUID))
- return Response.status(400).build();
+ throw new BadRequestException("Router does not exist");
NeutronRouter target = routerInterface.getRouter(routerUUID);
/*
@@ -486,7 +489,7 @@ public class NeutronRoutersNorthbound {
input.getSubnetUUID() != null) {
NeutronPort port = portInterface.getGatewayPort(input.getSubnetUUID());
if (port == null)
- return Response.status(404).build();
+ throw new ResourceNotFoundException("Port UUID not found");
input.setPortUUID(port.getID());
input.setID(target.getID());
input.setTenantID(target.getTenantID());
@@ -543,9 +546,18 @@ public class NeutronRoutersNorthbound {
if (input.getPortUUID() != null &&
input.getSubnetUUID() != null) {
NeutronPort port = portInterface.getPort(input.getPortUUID());
+ if (port == null) {
+ throw new ResourceNotFoundException("Port UUID not found");
+ }
+ if (port.getFixedIPs() == null) {
+ throw new ResourceNotFoundException("Port UUID jas no fixed IPs");
+ }
NeutronSubnet subnet = subnetInterface.getSubnet(input.getSubnetUUID());
+ if (subnet == null) {
+ throw new ResourceNotFoundException("Subnet UUID not found");
+ }
if (!subnet.isValidIP(port.getFixedIPs().get(0).getIpAddress()))
- return Response.status(409).build();
+ throw new ResourceConflictException("Target Port IP not in Target Subnet");
input.setID(target.getID());
input.setTenantID(target.getTenantID());
Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
@@ -566,6 +578,6 @@ public class NeutronRoutersNorthbound {
}
// have to specify either a port ID or a subnet ID
- return Response.status(400).build();
+ throw new BadRequestException("Must specify port id or subnet id or both");
}
}
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java
index dffac55c50..224fcb5f01 100644
--- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java
+++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java
@@ -33,13 +33,16 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.sal.utils.ServiceHelper;
/**
- * Open DOVE Northbound REST APIs.
- * This class provides REST APIs for managing open DOVE internals related to Subnets
+ * Neutron Northbound REST APIs for Subnets.
+ * This class provides REST APIs for managing neutron Subnets
*
*
*
@@ -142,7 +145,7 @@ public class NeutronSubnetsNorthbound {
+ RestMessages.SERVICEUNAVAILABLE.toString());
}
if (!subnetInterface.subnetExists(subnetUUID)) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("subnet UUID does not exist.");
}
if (fields.size() > 0) {
NeutronSubnet ans = subnetInterface.getSubnet(subnetUUID);
@@ -190,19 +193,19 @@ public class NeutronSubnetsNorthbound {
* *then* add the subnet to the cache
*/
if (subnetInterface.subnetExists(singleton.getID())) {
- return Response.status(400).build();
+ throw new BadRequestException("subnet UUID already exists");
}
if (!networkInterface.networkExists(singleton.getNetworkUUID())) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("network UUID does not exist.");
}
if (!singleton.isValidCIDR()) {
- return Response.status(400).build();
+ throw new BadRequestException("invaild CIDR");
}
if (!singleton.initDefaults()) {
throw new InternalServerErrorException("subnet object could not be initialized properly");
}
if (singleton.gatewayIP_Pool_overlap()) {
- return Response.status(409).build();
+ throw new ResourceConflictException("IP pool overlaps with gateway");
}
Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);
if (instances != null) {
@@ -240,20 +243,20 @@ public class NeutronSubnetsNorthbound {
throw new InternalServerErrorException("subnet object could not be initialized properly");
}
if (subnetInterface.subnetExists(test.getID())) {
- return Response.status(400).build();
+ throw new BadRequestException("subnet UUID already exists");
}
if (testMap.containsKey(test.getID())) {
- return Response.status(400).build();
+ throw new BadRequestException("subnet UUID already exists");
}
testMap.put(test.getID(), test);
if (!networkInterface.networkExists(test.getNetworkUUID())) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("network UUID does not exist.");
}
if (!test.isValidCIDR()) {
- return Response.status(400).build();
+ throw new BadRequestException("Invalid CIDR");
}
if (test.gatewayIP_Pool_overlap()) {
- return Response.status(409).build();
+ throw new ResourceConflictException("IP pool overlaps with gateway");
}
if (instances != null) {
for (Object instance : instances) {
@@ -312,10 +315,10 @@ public class NeutronSubnetsNorthbound {
* verify the subnet exists and there is only one delta provided
*/
if (!subnetInterface.subnetExists(subnetUUID)) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("subnet UUID does not exist.");
}
if (!input.isSingleton()) {
- return Response.status(400).build();
+ throw new BadRequestException("Only singleton edit supported");
}
NeutronSubnet delta = input.getSingleton();
NeutronSubnet original = subnetInterface.getSubnet(subnetUUID);
@@ -326,7 +329,7 @@ public class NeutronSubnetsNorthbound {
if (delta.getID() != null || delta.getTenantID() != null ||
delta.getIpVersion() != null || delta.getCidr() != null ||
delta.getAllocationPools() != null) {
- return Response.status(400).build();
+ throw new BadRequestException("Attribute edit blocked by Neutron");
}
Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);
@@ -378,7 +381,7 @@ public class NeutronSubnetsNorthbound {
* verify the subnet exists and it isn't currently in use
*/
if (!subnetInterface.subnetExists(subnetUUID)) {
- return Response.status(404).build();
+ throw new ResourceNotFoundException("subnet UUID does not exist.");
}
if (subnetInterface.subnetInUse(subnetUUID)) {
return Response.status(409).build();
diff --git a/opendaylight/sal/api/pom.xml b/opendaylight/sal/api/pom.xml
index 16868f5517..326755309d 100644
--- a/opendaylight/sal/api/pom.xml
+++ b/opendaylight/sal/api/pom.xml
@@ -15,7 +15,7 @@
sal
- 0.7.1-SNAPSHOT
+ 0.8.1-SNAPSHOT
bundle
diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Edge.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Edge.java
index 7f398db6f1..0dffee9c47 100644
--- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Edge.java
+++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Edge.java
@@ -85,6 +85,19 @@ public class Edge implements Serializable {
}
}
+ /**
+ * Create the reversed edge
+ * @return The reversed edge.
+ */
+ public Edge reverse() {
+ Edge re;
+ try {
+ re = new Edge(this.headNodeConnector, this.tailNodeConnector);
+ } catch (ConstructionException e) {
+ re = null;
+ }
+ return re;
+ }
/**
* getter of edge
*
diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java
index 31b3ec6a5a..ba2394131d 100644
--- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java
+++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java
@@ -17,6 +17,8 @@
package org.opendaylight.controller.sal.core;
import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
@@ -81,6 +83,39 @@ public class Path implements Serializable {
this.edges = edges;
}
+ /**
+ * Create the reversed path
+ * @return The reversed path
+ */
+ public Path reverse() {
+ int j = edges.size(); // size always > 0
+ Edge[] aEdges = new Edge[j];
+ for (Edge e : edges) {
+ j--;
+ aEdges[j] = e.reverse();
+ }
+ Path rp;
+ try {
+ rp = new Path(Arrays.asList(aEdges));
+ } catch (ConstructionException ce) {
+ rp = null;
+ }
+ return rp;
+ }
+
+ /**
+ * Return the list of nodes of this path, the first node is the start node
+ * @return the list of nodes
+ */
+ public List getNodes() {
+ List nl = new ArrayList();
+ nl.add(this.getStartNode());
+ for (Edge e : edges) {
+ nl.add(e.getHeadNodeConnector().getNode());
+ }
+ return nl;
+ }
+
/**
* Copy Construct for a path
*