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 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 data); - - @Deprecated - DataObject getConfigurationData(InstanceIdentifier data); /** * Creates a data modification transaction. - * + * * @return new blank data modification transaction. */ - DataModificationTransaction beginTransaction(); - - @Deprecated - public void registerChangeListener(InstanceIdentifier path, DataChangeListener changeListener); - - @Deprecated - public void unregisterChangeListener(InstanceIdentifier 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 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 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 data) { - throw new UnsupportedOperationException("Deprecated"); - } - - @Override - @Deprecated - public DataObject getConfigurationData(InstanceIdentifier data) { - throw new UnsupportedOperationException("Deprecated"); - } - - @Override - @Deprecated - public void registerChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { - throw new UnsupportedOperationException("Deprecated"); - } - - @Override - @Deprecated - public void unregisterChangeListener(InstanceIdentifier 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 path) { - return readOperationalData(path); - } - - override registerChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { - } - - override unregisterChangeListener(InstanceIdentifier 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 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 path, DataChangeListener changeListener) { - getDataBrokerChecked().registerChangeListener(path, changeListener); - } - - @Override - @Deprecated - public void unregisterChangeListener(InstanceIdentifier path, - DataChangeListener changeListener) { - getDataBrokerChecked().unregisterChangeListener(path, changeListener); - } - @Override @Deprecated public DataObject readConfigurationData(InstanceIdentifier 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: - * + * *
    *
  1. {@link Consumer} invokes * {@link ConsumerSession#rpc(QName, CompositeNode)} @@ -42,31 +42,31 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; * {@link RpcResult} *
  2. {@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 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 path, DataChangeListener changeListener) { - - } - - @Override - public void unregisterChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { - - } - @Override public DataObject readConfigurationData(InstanceIdentifier 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 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 path, DataChangeListener changeListener) { - throw new UnsupportedOperationException("Deprecated"); - } - - @Override - public void unregisterChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { - throw new UnsupportedOperationException("Deprecated"); - } - @Override public DataObject readConfigurationData(InstanceIdentifier 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 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 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 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 exType, + String exMessageToContain, Class 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 *