From: Alessandro Boch Date: Tue, 25 Feb 2014 23:51:11 +0000 (+0000) Subject: Merge "Add reverse() method in Edge and Path classes" X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~377 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=2c146f582dee58e36dc22505b4c6bedb4641342f;hp=142c513a58c066cc9fbe4b256320f809034ba365 Merge "Add reverse() method in Edge and Path classes" --- diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index 6e178ca2c9..acda40035f 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -113,6 +113,8 @@ 1.7 1.3.1 + 2.4.3 + ${project.build.directory}/generated-sources/xtend-gen @@ -1164,6 +1166,11 @@ + + org.eclipse.xtend + org.eclipse.xtend.lib + ${xtend.version} + org.opendaylight.controller sal-common @@ -1442,16 +1449,6 @@ config-persister-impl ${netconf.version} - - ${project.groupId} - ietf-netconf-monitoring - ${netconf.version} - - - ${project.groupId} - ietf-netconf-monitoring-extension - ${netconf.version} - @@ -1991,6 +1988,21 @@ ${java.version.target} + + org.eclipse.xtend + xtend-maven-plugin + ${xtend.version} + + + + compile + + + ${xtend.dstdir} + + + + 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 newInstances, reusedInstances, recreatedInstances; /** - * - * @param newInstances - * newly created instances - * @param reusedInstances - * reused instances - * @param recreatedInstances - * recreated instances + * @param newInstances newly created instances + * @param reusedInstances reused instances + * @param recreatedInstances recreated instances */ - @ConstructorProperties({ "newInstances", "reusedInstances", - "recreatedInstances" }) + @ConstructorProperties({"newInstances", "reusedInstances", + "recreatedInstances"}) public CommitStatus(List newInstances, - List reusedInstances, - List recreatedInstances) { + List reusedInstances, + List recreatedInstances) { this.newInstances = Collections.unmodifiableList(newInstances); this.reusedInstances = Collections.unmodifiableList(reusedInstances); this.recreatedInstances = Collections @@ -40,7 +35,6 @@ public class CommitStatus { } /** - * * @return list of objectNames representing newly created instances */ public List getNewInstances() { @@ -48,7 +42,6 @@ public class CommitStatus { } /** - * * @return list of objectNames representing reused instances */ public List getReusedInstances() { @@ -56,7 +49,6 @@ public class CommitStatus { } /** - * * @return list of objectNames representing recreated instances */ public List getRecreatedInstances() { @@ -72,7 +64,7 @@ public class CommitStatus { result = prime * result + ((recreatedInstances == null) ? 0 : recreatedInstances - .hashCode()); + .hashCode()); result = prime * result + ((reusedInstances == null) ? 0 : reusedInstances.hashCode()); return result; @@ -80,28 +72,37 @@ public class CommitStatus { @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (obj == null) + } + if (obj == null) { return false; - if (getClass() != obj.getClass()) + } + if (getClass() != obj.getClass()) { return false; + } CommitStatus other = (CommitStatus) obj; if (newInstances == null) { - if (other.newInstances != null) + if (other.newInstances != null) { return false; - } else if (!newInstances.equals(other.newInstances)) + } + } else if (!newInstances.equals(other.newInstances)) { return false; + } if (recreatedInstances == null) { - if (other.recreatedInstances != null) + if (other.recreatedInstances != null) { return false; - } else if (!recreatedInstances.equals(other.recreatedInstances)) + } + } else if (!recreatedInstances.equals(other.recreatedInstances)) { return false; + } if (reusedInstances == null) { - if (other.reusedInstances != null) + if (other.reusedInstances != null) { return false; - } else if (!reusedInstances.equals(other.reusedInstances)) + } + } else if (!reusedInstances.equals(other.reusedInstances)) { return false; + } return true; } diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java index 3baa1039e0..d60e608617 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java @@ -11,6 +11,7 @@ import org.opendaylight.controller.config.api.ModuleIdentifier; import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants; import javax.annotation.concurrent.ThreadSafe; +import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import java.util.Arrays; import java.util.HashMap; @@ -46,8 +47,8 @@ public class ObjectNameUtil { public static ObjectName createON(String on) { try { return new ObjectName(on); - } catch (Exception e) { - throw new RuntimeException(e); + } catch (MalformedObjectNameException e) { + throw new IllegalArgumentException(e); } } @@ -63,8 +64,8 @@ public class ObjectNameUtil { Hashtable table = new Hashtable<>(attribs); try { return new ObjectName(domain, table); - } catch (Exception e) { - throw new RuntimeException(e); + } catch (MalformedObjectNameException e) { + throw new IllegalArgumentException(e); } } @@ -116,8 +117,7 @@ public class ObjectNameUtil { public static String getServiceQName(ObjectName objectName) { checkType(objectName, TYPE_SERVICE_REFERENCE); String quoted = objectName.getKeyProperty(SERVICE_QNAME_KEY); - String result = unquoteAndUnescape(objectName, quoted); - return result; + return unquoteAndUnescape(objectName, quoted); } // ObjectName supports quotation and ignores tokens like =, but fails to ignore ? sign. @@ -292,8 +292,8 @@ public class ObjectNameUtil { } } - public static void checkTypeOneOf(ObjectName objectName, String ... types) { - for(String type: types) { + public static void checkTypeOneOf(ObjectName objectName, String... types) { + for (String type : types) { if (type.equals(objectName.getKeyProperty(TYPE_KEY))) { return; } @@ -304,10 +304,12 @@ public class ObjectNameUtil { public static ObjectName createModulePattern(String moduleName, String instanceName) { - if (moduleName == null) + if (moduleName == null) { moduleName = "*"; - if (instanceName == null) + } + if (instanceName == null) { instanceName = "*"; + } // do not return object names containing transaction name ObjectName namePattern = ObjectNameUtil .createON(ObjectNameUtil.ON_DOMAIN + ":" @@ -343,13 +345,15 @@ public class ObjectNameUtil { String expectedType) { checkType(objectName, expectedType); String factoryName = getFactoryName(objectName); - if (factoryName == null) + if (factoryName == null) { throw new IllegalArgumentException( "ObjectName does not contain module name"); + } String instanceName = getInstanceName(objectName); - if (instanceName == null) + if (instanceName == null) { throw new IllegalArgumentException( "ObjectName does not contain instance name"); + } return new ModuleIdentifier(factoryName, instanceName); } diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/constants/ConfigRegistryConstants.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/constants/ConfigRegistryConstants.java index 81a29bf7b3..1d9563bf4e 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/constants/ConfigRegistryConstants.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/constants/ConfigRegistryConstants.java @@ -7,6 +7,7 @@ */ package org.opendaylight.controller.config.api.jmx.constants; +import javax.management.MalformedObjectNameException; import javax.management.ObjectName; public class ConfigRegistryConstants { @@ -19,7 +20,7 @@ public class ConfigRegistryConstants { public static final ObjectName OBJECT_NAME = createONWithDomainAndType(TYPE_CONFIG_REGISTRY); - public static String GET_AVAILABLE_MODULE_NAMES_ATTRIBUT_NAME = "AvailableModuleNames"; + public static final String GET_AVAILABLE_MODULE_NAMES_ATTRIBUT_NAME = "AvailableModuleNames"; public static ObjectName createONWithDomainAndType(String type) { return createON(ON_DOMAIN, TYPE_KEY, type); @@ -28,8 +29,8 @@ public class ConfigRegistryConstants { public static ObjectName createON(String name, String key, String value) { try { return new ObjectName(name, key, value); - } catch (Exception e) { - throw new RuntimeException(e); + } catch (MalformedObjectNameException e) { + throw new IllegalArgumentException(e); } } diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/Module.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/Module.java index dd11b7503f..1b16ec8284 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/Module.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/Module.java @@ -7,11 +7,11 @@ */ package org.opendaylight.controller.config.spi; -import javax.annotation.concurrent.NotThreadSafe; - import org.opendaylight.controller.config.api.ModuleIdentifier; import org.opendaylight.yangtools.concepts.Identifiable; +import javax.annotation.concurrent.NotThreadSafe; + /** * Represents one service that is to be configured. These methods need to be @@ -20,7 +20,7 @@ import org.opendaylight.yangtools.concepts.Identifiable; * ConfigBeans. *

* 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 39682fa6b4..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; @@ -105,19 +108,19 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe private List lastListOfFactories = Collections.emptyList(); @GuardedBy("this") // switched in every 2ndPC - private CloseableServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry(); + private CloseableServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry(); // constructor public ConfigRegistryImpl(ModuleFactoriesResolver resolver, - MBeanServer configMBeanServer, CodecRegistry codecRegistry) { + MBeanServer configMBeanServer, CodecRegistry codecRegistry) { this(resolver, configMBeanServer, new BaseJMXRegistrator(configMBeanServer), codecRegistry); } // constructor public ConfigRegistryImpl(ModuleFactoriesResolver resolver, - MBeanServer configMBeanServer, - BaseJMXRegistrator baseJMXRegistrator, CodecRegistry codecRegistry) { + MBeanServer configMBeanServer, + BaseJMXRegistrator baseJMXRegistrator, CodecRegistry codecRegistry) { this.resolver = resolver; this.beanToOsgiServiceManager = new BeanToOsgiServiceManager(); this.configMBeanServer = configMBeanServer; @@ -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; } @@ -181,6 +184,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe * {@inheritDoc} */ @Override + @SuppressWarnings("PMD.AvoidCatchingThrowable") public synchronized CommitStatus commitConfig(ObjectName transactionControllerON) throws ConflictingVersionException, ValidationException { final String transactionName = ObjectNameUtil @@ -188,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( @@ -208,10 +213,9 @@ 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 + // javax.xml.ws.spi.FactoryFinder$ConfigurationError isHealthy = false; logger.error("Configuration Transaction failed on 2PC, server is unhealthy", t); if (t instanceof RuntimeException) { @@ -225,14 +229,14 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe } private CommitStatus secondPhaseCommit(ConfigTransactionControllerInternal configTransactionController, - CommitInfo commitInfo) { + CommitInfo commitInfo, ConfigTransactionLookupRegistry txLookupRegistry) { // close instances which were destroyed by the user, including // (hopefully) runtime beans for (DestroyedModule toBeDestroyed : commitInfo .getDestroyedFromPreviousTransactions()) { toBeDestroyed.close(); // closes instance (which should close - // runtime jmx registrator), + // runtime jmx registrator), // also closes osgi registration and ModuleJMXRegistrator // registration currentConfig.remove(toBeDestroyed.getIdentifier()); @@ -254,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); @@ -264,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<>(); @@ -278,10 +283,11 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe for (ModuleIdentifier moduleIdentifier : orderedModuleIdentifiers) { ModuleInternalTransactionalInfo entry = commitInfo.getCommitted() .get(moduleIdentifier); - if (entry == null) + if (entry == null) { throw new NullPointerException("Module not found " + moduleIdentifier); - Module module = entry.getModule(); + } + ObjectName primaryReadOnlyON = ObjectNameUtil .createReadOnlyModuleON(moduleIdentifier); @@ -298,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); @@ -326,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 @@ -342,10 +350,10 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe // register to OSGi if (osgiRegistration == null) { ModuleFactory moduleFactory = entry.getModuleFactory(); - if(moduleFactory != null) { + 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."); @@ -360,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()); @@ -382,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; } @@ -401,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 {}", @@ -485,7 +496,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe */ @Override public Set lookupConfigBeans(String moduleName, - String instanceName) { + String instanceName) { ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName, instanceName); return baseJMXRegistrator.queryNames(namePattern, null); @@ -504,11 +515,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe */ @Override public Set lookupRuntimeBeans(String moduleName, - String instanceName) { - if (moduleName == null) + String instanceName) { + if (moduleName == null) { moduleName = "*"; - if (instanceName == null) + } + if (instanceName == null) { instanceName = "*"; + } ObjectName namePattern = ObjectNameUtil.createRuntimeBeanPattern( moduleName, instanceName); return baseJMXRegistrator.queryNames(namePattern, null); @@ -646,18 +659,18 @@ class TransactionsHolder { * {@link ConfigTransactionControllerInternal} instances, because platform * MBeanServer transforms mbeans into another representation. Map is cleaned * 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"); @@ -671,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 - .entrySet().iterator(); it.hasNext();) { - Entry entry = it + for (Iterator>> it = transactions + .entrySet().iterator(); it.hasNext(); ) { + 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 0ec6969802..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; @@ -53,7 +54,7 @@ import static java.lang.String.format; class ConfigTransactionControllerImpl implements ConfigTransactionControllerInternal, ConfigTransactionControllerImplMXBean, - Identifiable{ + Identifiable { private static final Logger logger = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class); private final ConfigTransactionLookupRegistry txLookupRegistry; @@ -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; @@ -124,12 +126,12 @@ class ConfigTransactionControllerImpl implements List toBeAdded = new ArrayList<>(); List toBeRemoved = new ArrayList<>(); - for(ModuleFactory moduleFactory: factoriesHolder.getModuleFactories()) { - if (oldSet.contains(moduleFactory) == false){ + for (ModuleFactory moduleFactory : factoriesHolder.getModuleFactories()) { + if (oldSet.contains(moduleFactory) == false) { toBeAdded.add(moduleFactory); } } - for(ModuleFactory moduleFactory: lastListOfFactories){ + for (ModuleFactory moduleFactory : lastListOfFactories) { if (newSet.contains(moduleFactory) == false) { toBeRemoved.add(moduleFactory); } @@ -151,7 +153,7 @@ class ConfigTransactionControllerImpl implements } // remove modules belonging to removed factories - for(ModuleFactory removedFactory: toBeRemoved){ + for (ModuleFactory removedFactory : toBeRemoved) { List modulesOfRemovedFactory = dependencyResolverManager.findAllByFactory(removedFactory); for (ModuleIdentifier name : modulesOfRemovedFactory) { destroyModule(name); @@ -189,7 +191,7 @@ class ConfigTransactionControllerImpl implements @Override public synchronized ObjectName createModule(String factoryName, - String instanceName) throws InstanceAlreadyExistsException { + String instanceName) throws InstanceAlreadyExistsException { transactionStatus.checkNotCommitStarted(); transactionStatus.checkNotAborted(); @@ -213,11 +215,11 @@ class ConfigTransactionControllerImpl implements throws InstanceAlreadyExistsException { logger.debug("Adding module {} to transaction {}", moduleIdentifier, this); - if (moduleIdentifier.equals(module.getIdentifier())==false) { + if (moduleIdentifier.equals(module.getIdentifier()) == false) { throw new IllegalStateException("Incorrect name reported by module. Expected " - + moduleIdentifier + ", got " + module.getIdentifier()); + + moduleIdentifier + ", got " + module.getIdentifier()); } - if (dependencyResolver.getIdentifier().equals(moduleIdentifier) == false ) { + if (dependencyResolver.getIdentifier().equals(moduleIdentifier) == false) { throw new IllegalStateException("Incorrect name reported by dependency resolver. Expected " + moduleIdentifier + ", got " + dependencyResolver.getIdentifier()); } @@ -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; } @@ -271,7 +272,7 @@ class ConfigTransactionControllerImpl implements // first remove refNames, it checks for objectname existence try { writableSRRegistry.removeServiceReferences( - ObjectNameUtil.createTransactionModuleON(getTransactionName(),moduleIdentifier)); + ObjectNameUtil.createTransactionModuleON(getTransactionName(), moduleIdentifier)); } catch (InstanceNotFoundException e) { logger.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry); throw new IllegalStateException("Possible code error: cannot find " + moduleIdentifier, e); @@ -294,8 +295,9 @@ class ConfigTransactionControllerImpl implements @Override public synchronized void validateConfig() throws ValidationException { - if (configBeanModificationDisabled.get()) + if (configBeanModificationDisabled.get()) { throw new IllegalStateException("Cannot start validation"); + } configBeanModificationDisabled.set(true); try { validate_noLocks(); @@ -383,7 +385,7 @@ class ConfigTransactionControllerImpl implements logger.error("Commit failed on {} in transaction {}", name, getTransactionIdentifier(), e); internalAbort(); - throw new RuntimeException( + throw new IllegalStateException( format("Error - getInstance() failed for %s in transaction %s", name, getTransactionIdentifier()), e); } @@ -393,8 +395,6 @@ class ConfigTransactionControllerImpl implements logger.trace("Committed configuration {}", getTransactionIdentifier()); transactionStatus.setCommitted(); - // unregister this and all modules from jmx - close(); return dependencyResolverManager.getSortedModuleIdentifiers(); } @@ -412,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 @@ -571,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/ServiceReferenceRegistryImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java index 0faa32b7dc..bf35fd1ed8 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java @@ -195,7 +195,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe this.serviceReferenceRegistrator = serviceReferenceRegistratorFactory.create(); - Map> factoryNamesToQNames = new HashMap<>(); + Map> modifiableFactoryNamesToQNames = new HashMap<>(); Set allAnnotations = new HashSet<>(); Set allQNames = new HashSet<>(); for (Entry entry : factories.entrySet()) { @@ -210,27 +210,27 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe } allAnnotations.addAll(siAnnotations); allQNames.addAll(qNames); - factoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames)); + modifiableFactoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames)); } - this.factoryNamesToQNames = Collections.unmodifiableMap(factoryNamesToQNames); + this.factoryNamesToQNames = Collections.unmodifiableMap(modifiableFactoryNamesToQNames); this.allQNames = Collections.unmodifiableSet(allQNames); // fill namespacesToAnnotations - Map> namespacesToAnnotations = + Map> modifiableNamespacesToAnnotations = new HashMap<>(); for (ServiceInterfaceAnnotation sia : allAnnotations) { - Map ofNamespace = namespacesToAnnotations.get(sia.namespace()); + Map ofNamespace = modifiableNamespacesToAnnotations.get(sia.namespace()); if (ofNamespace == null) { ofNamespace = new HashMap<>(); - namespacesToAnnotations.put(sia.namespace(), ofNamespace); + modifiableNamespacesToAnnotations.put(sia.namespace(), ofNamespace); } if (ofNamespace.containsKey(sia.localName())) { logger.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}", - sia.namespace(), sia.localName(), namespacesToAnnotations); + sia.namespace(), sia.localName(), modifiableNamespacesToAnnotations); throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName()); } ofNamespace.put(sia.localName(), sia); } - this.namespacesToAnnotations = Collections.unmodifiableMap(namespacesToAnnotations); + this.namespacesToAnnotations = Collections.unmodifiableMap(modifiableNamespacesToAnnotations); // copy refNames logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames); } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionIdentifier.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionIdentifier.java index 28bd613648..15c69bf25f 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionIdentifier.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionIdentifier.java @@ -28,15 +28,18 @@ public class TransactionIdentifier implements Identifier { @Override public boolean equals(Object o) { - if (this == o) + if (this == o) { return true; - if (o == null || getClass() != o.getClass()) + } + if (o == null || getClass() != o.getClass()) { return false; + } TransactionIdentifier that = (TransactionIdentifier) o; - if (name != null ? !name.equals(that.name) : that.name != null) + if (name != null ? !name.equals(that.name) : that.name != null) { return false; + } return true; } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionStatus.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionStatus.java index a25062074b..f86d6b1d81 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionStatus.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionStatus.java @@ -48,18 +48,21 @@ public class TransactionStatus { } public synchronized void checkNotCommitStarted() { - if (secondPhaseCommitStarted == true) + if (secondPhaseCommitStarted == true) { throw new IllegalStateException("Commit was triggered"); + } } public synchronized void checkCommitStarted() { - if (secondPhaseCommitStarted == false) + if (secondPhaseCommitStarted == false) { throw new IllegalStateException("Commit was not triggered"); + } } public synchronized void checkNotAborted() { - if (aborted == true) + if (aborted == true) { throw new IllegalStateException("Configuration was aborted"); + } } public synchronized void checkNotCommitted() { 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 ec9678fd2d..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 @@ -39,7 +39,7 @@ import static java.lang.String.format; * during validation. Tracks dependencies for ordering purposes. */ final class DependencyResolverImpl implements DependencyResolver, - Comparable { + Comparable { private static final Logger logger = LoggerFactory.getLogger(DependencyResolverImpl.class); private final ModulesHolder modulesHolder; @@ -74,15 +74,15 @@ final class DependencyResolverImpl implements DependencyResolver, throw new NullPointerException( "Parameter 'expectedServiceInterface' is null"); } - if (jmxAttribute == null) + if (jmxAttribute == null) { throw new NullPointerException("Parameter 'jmxAttribute' is null"); + } JmxAttributeValidationException.checkNotNull(dependentReadOnlyON, "is null, expected dependency implementing " + expectedServiceInterface, jmxAttribute); - // check that objectName belongs to this transaction - this should be // stripped // in DynamicWritableWrapper @@ -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); @@ -135,7 +135,7 @@ final class DependencyResolverImpl implements DependencyResolver, //TODO: check for cycles @Override public T resolveInstance(Class expectedType, ObjectName dependentReadOnlyON, - JmxAttribute jmxAttribute) { + JmxAttribute jmxAttribute) { if (expectedType == null || dependentReadOnlyON == null || jmxAttribute == null) { throw new IllegalArgumentException(format( "Null parameters not allowed, got %s %s %s", expectedType, @@ -161,8 +161,7 @@ final class DependencyResolverImpl implements DependencyResolver, throw new JmxAttributeValidationException(message, jmxAttribute); } try { - T result = expectedType.cast(instance); - return result; + return expectedType.cast(instance); } catch (ClassCastException e) { String message = format( "Instance cannot be cast to expected type. Instance class is %s , " @@ -178,7 +177,7 @@ final class DependencyResolverImpl implements DependencyResolver, IdentityCodec identityCodec = codecRegistry.getIdentityCodec(); Class deserialized = identityCodec.deserialize(qName); if (deserialized == null) { - throw new RuntimeException("Unable to retrieve identity class for " + qName + ", null response from " + throw new IllegalStateException("Unable to retrieve identity class for " + qName + ", null response from " + codecRegistry); } if (expectedBaseClass.isAssignableFrom(deserialized)) { @@ -194,7 +193,7 @@ final class DependencyResolverImpl implements DependencyResolver, public void validateIdentity(IdentityAttributeRef identityRef, Class expectedBaseClass, JmxAttribute jmxAttribute) { try { resolveIdentity(identityRef, expectedBaseClass); - } catch(Exception e) { + } catch (Exception e) { throw JmxAttributeValidationException.wrap(e, jmxAttribute); } } @@ -215,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, @@ -224,8 +223,8 @@ final class DependencyResolverImpl implements DependencyResolver, } private static int getMaxDepth(DependencyResolverImpl impl, - DependencyResolverManager manager, - LinkedHashSet chainForDetectingCycles) { + DependencyResolverManager manager, + LinkedHashSet chainForDetectingCycles) { int maxDepth = 0; LinkedHashSet chainForDetectingCycles2 = new LinkedHashSet<>( chainForDetectingCycles); @@ -258,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 72% 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 0a4ceacb43..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,38 +5,39 @@ * 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; - -import javax.annotation.Nullable; +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.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.spi.ModuleFactory; import org.opendaylight.yangtools.concepts.Identifiable; +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; } @@ -57,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/dynamicmbean/AbstractDynamicWrapper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java index 6f0d1b2682..7e48af1caa 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java @@ -55,7 +55,6 @@ import static java.lang.String.format; * requests (getAttribute, setAttribute, invoke) into the actual instance, but * provides additional functionality - namely it disallows setting attribute on * a read only wrapper. - * */ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { private static final Logger logger = LoggerFactory @@ -71,9 +70,9 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { protected final MBeanServer internalServer; public AbstractDynamicWrapper(Module module, boolean writable, - ModuleIdentifier moduleIdentifier, - ObjectName thisWrapperObjectName, MBeanOperationInfo[] dOperations, - MBeanServer internalServer, MBeanServer configMBeanServer) { + ModuleIdentifier moduleIdentifier, + ObjectName thisWrapperObjectName, MBeanOperationInfo[] dOperations, + MBeanServer internalServer, MBeanServer configMBeanServer) { this.writable = writable; this.module = module; @@ -98,10 +97,10 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { * case unregister the module and remove listener. */ private final NotificationListener registerActualModule(Module module, - final ObjectName thisWrapperObjectName, - final ObjectName objectNameInternal, - final MBeanServer internalServer, - final MBeanServer configMBeanServer) { + final ObjectName thisWrapperObjectName, + final ObjectName objectNameInternal, + final MBeanServer internalServer, + final MBeanServer configMBeanServer) { try { internalServer.registerMBean(module, objectNameInternal); @@ -116,7 +115,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { public void handleNotification(Notification n, Object handback) { if (n instanceof MBeanServerNotification && n.getType() - .equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) { + .equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) { if (((MBeanServerNotification) n).getMBeanName().equals( thisWrapperObjectName)) { try { @@ -142,8 +141,8 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { } private static MBeanInfo generateMBeanInfo(String className, Module module, - Map attributeHolderMap, - MBeanOperationInfo[] dOperations, Set> jmxInterfaces) { + Map attributeHolderMap, + MBeanOperationInfo[] dOperations, Set> jmxInterfaces) { String dDescription = findDescription(module.getClass(), jmxInterfaces); MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[0]; @@ -170,9 +169,9 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { // inspect all exported interfaces ending with MXBean, extract getters & // setters into attribute holder private static Map buildMBeanInfo(Module module, - boolean writable, ModuleIdentifier moduleIdentifier, - Set> jmxInterfaces, MBeanServer internalServer, - ObjectName internalObjectName) { + boolean writable, ModuleIdentifier moduleIdentifier, + Set> jmxInterfaces, MBeanServer internalServer, + ObjectName internalObjectName) { // internal variables for describing MBean elements Set methods = new HashSet<>(); @@ -217,7 +216,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { } AttributeHolder attributeHolder = new AttributeHolder( attribName, module, attributeMap.get(attribName) - .getType(), writable, ifc, description); + .getType(), writable, ifc, description); attributeHolderMap.put(attribName, attributeHolder); } } @@ -257,7 +256,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { } - if(isDependencyListAttr(attributeName, obj)) { + if (isDependencyListAttr(attributeName, obj)) { obj = fixDependencyListAttribute(obj); } @@ -265,14 +264,16 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { } private Object fixDependencyListAttribute(Object attribute) { - if(attribute.getClass().isArray() == false) + if (attribute.getClass().isArray() == false) { throw new IllegalArgumentException("Unexpected attribute type, should be an array, but was " + attribute.getClass()); + } for (int i = 0; i < Array.getLength(attribute); i++) { Object on = Array.get(attribute, i); - if(on instanceof ObjectName == false) + if (on instanceof ObjectName == false) { throw new IllegalArgumentException("Unexpected attribute type, should be an ObjectName, but was " + on.getClass()); + } on = fixObjectName((ObjectName) on); Array.set(attribute, i, on); @@ -282,8 +283,9 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { } private boolean isDependencyListAttr(String attributeName, Object attribute) { - if (attributeHolderMap.containsKey(attributeName) == false) + if (attributeHolderMap.containsKey(attributeName) == false) { return false; + } AttributeHolder attributeHolder = attributeHolderMap.get(attributeName); @@ -294,15 +296,17 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper { } protected ObjectName fixObjectName(ObjectName on) { - if (!ObjectNameUtil.ON_DOMAIN.equals(on.getDomain())) + if (!ObjectNameUtil.ON_DOMAIN.equals(on.getDomain())) { throw new IllegalArgumentException("Wrong domain, expected " + ObjectNameUtil.ON_DOMAIN + " setter on " + on); + } // if on contains transaction name, remove it String transactionName = ObjectNameUtil.getTransactionName(on); - if (transactionName != null) + if (transactionName != null) { return ObjectNameUtil.withoutTransactionName(on); - else + } else { return on; + } } @Override diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsHelper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsHelper.java index 64664f7980..f3e1b4e705 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsHelper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsHelper.java @@ -7,15 +7,15 @@ */ package org.opendaylight.controller.config.manager.impl.dynamicmbean; +import org.opendaylight.controller.config.api.annotations.Description; + import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Set; -import org.opendaylight.controller.config.api.annotations.Description; - -class AnnotationsHelper { +public class AnnotationsHelper { /** * Look for annotation specified by annotationType on method. First observe diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java index 9dd6a2269e..044f7a9ada 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java @@ -40,9 +40,9 @@ class AttributeHolder { } public AttributeHolder(String name, Object object, String returnType, - boolean writable, - @Nullable RequireInterface requireInterfaceAnnotation, - String description) { + boolean writable, + @Nullable RequireInterface requireInterfaceAnnotation, + String description) { if (name == null) { throw new NullPointerException(); } @@ -65,7 +65,7 @@ class AttributeHolder { /** * @return annotation if setter sets ObjectName or ObjectName[], and is - * annotated. Return null otherwise. + * annotated. Return null otherwise. */ RequireInterface getRequireInterfaceOrNull() { return requireInterfaceAnnotation; @@ -98,7 +98,7 @@ class AttributeHolder { * @param setter * @param jmxInterfaces * @return empty string if no annotation is found, or list of descriptions - * separated by newline + * separated by newline */ static String findDescription(Method setter, Set> jmxInterfaces) { List descriptions = AnnotationsHelper @@ -112,21 +112,21 @@ class AttributeHolder { * * @param setter * @param inspectedInterfaces - * @throws IllegalStateException - * if more than one value is specified by found annotations - * @throws IllegalArgumentException - * if set of exported interfaces contains non interface type * @return null if no annotation is found, otherwise return the annotation + * @throws IllegalStateException if more than one value is specified by found annotations + * @throws IllegalArgumentException if set of exported interfaces contains non interface type */ static RequireInterface findRequireInterfaceAnnotation(final Method setter, - Set> inspectedInterfaces) { + Set> inspectedInterfaces) { // only allow setX(ObjectName y) or setX(ObjectName[] y) or setX(List y) to continue - if (setter.getParameterTypes().length > 1) + if (setter.getParameterTypes().length > 1) { return null; - if(PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.contains(setter.getParameterTypes()[0]) == false) + } + if (PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.contains(setter.getParameterTypes()[0]) == false) { return null; + } List foundRequireInterfaces = AnnotationsHelper .findMethodAnnotationInSuperClassesAndIfcs(setter, RequireInterface.class, inspectedInterfaces); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java index 16f7cf024a..adc8168af5 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java @@ -10,25 +10,21 @@ package org.opendaylight.controller.config.manager.impl.factoriesresolver; import org.opendaylight.controller.config.spi.ModuleFactory; import org.osgi.framework.BundleContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.util.Map.Entry; -import java.util.Set; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Collections; +import java.util.Map.Entry; +import java.util.Set; import java.util.TreeSet; -import java.util.Collection; -import java.util.ArrayList; /** * Hold sorted ConfigMBeanFactories by their module names. Check that module * names are globally unique. */ public class HierarchicalConfigMBeanFactoriesHolder { - private static final Logger logger = LoggerFactory - .getLogger(HierarchicalConfigMBeanFactoriesHolder.class); private final Map> moduleNamesToConfigBeanFactories; private final Set moduleNames; diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/InternalJMXRegistrator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/InternalJMXRegistrator.java index 5d771560a5..98f0908dc7 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/InternalJMXRegistrator.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/InternalJMXRegistrator.java @@ -7,22 +7,24 @@ */ package org.opendaylight.controller.config.manager.impl.jmx; -import java.io.Closeable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.concurrent.GuardedBy; import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; import javax.management.JMX; +import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; +import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import javax.management.QueryExp; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.io.Closeable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class InternalJMXRegistrator implements Closeable { private static final Logger logger = LoggerFactory @@ -38,7 +40,7 @@ public class InternalJMXRegistrator implements Closeable { private final ObjectName on; InternalJMXRegistration(InternalJMXRegistrator internalJMXRegistrator, - ObjectName on) { + ObjectName on) { this.internalJMXRegistrator = internalJMXRegistrator; this.on = on; } @@ -54,13 +56,11 @@ public class InternalJMXRegistrator implements Closeable { private final List children = new ArrayList<>(); public synchronized InternalJMXRegistration registerMBean(Object object, - ObjectName on) throws InstanceAlreadyExistsException { + ObjectName on) throws InstanceAlreadyExistsException { try { configMBeanServer.registerMBean(object, on); - } catch (InstanceAlreadyExistsException e) { - throw e; - } catch (Exception e) { - throw new RuntimeException(e); + } catch (MBeanRegistrationException | NotCompliantMBeanException e) { + throw new IllegalStateException(e); } registeredObjectNames.add(on); return new InternalJMXRegistration(this, on); @@ -69,14 +69,13 @@ public class InternalJMXRegistrator implements Closeable { private synchronized void unregisterMBean(ObjectName on) { // first check that on was registered using this instance boolean removed = registeredObjectNames.remove(on); - if (!removed) - throw new IllegalStateException( - "Cannot unregister - ObjectName not found in 'registeredObjectNames': " - + on); + if (!removed) { + throw new IllegalStateException("Cannot unregister - ObjectName not found in 'registeredObjectNames': " + on); + } try { configMBeanServer.unregisterMBean(on); - } catch (Exception e) { - throw new RuntimeException(e); + } catch (InstanceNotFoundException | MBeanRegistrationException e) { + throw new IllegalStateException(e); } } @@ -112,7 +111,7 @@ public class InternalJMXRegistrator implements Closeable { } public T newMBeanProxy(ObjectName objectName, Class interfaceClass, - boolean notificationBroadcaster) { + boolean notificationBroadcaster) { return JMX.newMBeanProxy(configMBeanServer, objectName, interfaceClass, notificationBroadcaster); } @@ -123,7 +122,7 @@ public class InternalJMXRegistrator implements Closeable { } public T newMXBeanProxy(ObjectName objectName, Class interfaceClass, - boolean notificationBroadcaster) { + boolean notificationBroadcaster) { return JMX.newMXBeanProxy(configMBeanServer, objectName, interfaceClass, notificationBroadcaster); } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReference.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReference.java index 849f75234f..cd74ddf756 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReference.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ServiceReference.java @@ -25,13 +25,21 @@ public class ServiceReference { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } ServiceReference that = (ServiceReference) o; - if (!refName.equals(that.refName)) return false; - if (!serviceInterfaceName.equals(that.serviceInterfaceName)) return false; + if (!refName.equals(that.refName)) { + return false; + } + if (!serviceInterfaceName.equals(that.serviceInterfaceName)) { + return false; + } return true; } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionJMXRegistrator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionJMXRegistrator.java index b371c3f170..6fd2a2fc65 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionJMXRegistrator.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionJMXRegistrator.java @@ -7,15 +7,14 @@ */ package org.opendaylight.controller.config.manager.impl.jmx; -import java.io.Closeable; -import java.util.Set; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator.InternalJMXRegistration; import javax.management.InstanceAlreadyExistsException; import javax.management.ObjectName; import javax.management.QueryExp; - -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; -import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator.InternalJMXRegistration; +import java.io.Closeable; +import java.util.Set; /** * Contains constraints on passed {@link ObjectName} parameters. Only allow (un) @@ -26,7 +25,7 @@ public class TransactionJMXRegistrator implements Closeable { private final String transactionName; TransactionJMXRegistrator(InternalJMXRegistrator internalJMXRegistrator, - String transactionName) { + String transactionName) { this.childJMXRegistrator = internalJMXRegistrator.createChild(); this.transactionName = transactionName; } @@ -46,10 +45,11 @@ public class TransactionJMXRegistrator implements Closeable { public TransactionJMXRegistration registerMBean(Object object, ObjectName on) throws InstanceAlreadyExistsException { - if (!transactionName.equals(ObjectNameUtil.getTransactionName(on))) + if (!transactionName.equals(ObjectNameUtil.getTransactionName(on))) { throw new IllegalArgumentException( "Transaction name mismatch between expected " + transactionName + " " + "and " + on); + } ObjectNameUtil.checkType(on, ObjectNameUtil.TYPE_CONFIG_TRANSACTION); return new TransactionJMXRegistration( childJMXRegistrator.registerMBean(object, on)); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java index 2a533ab9a3..1e94e5e9c0 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java @@ -53,7 +53,7 @@ public class BundleContextBackedModuleFactoriesResolver implements if(factory == null) { throw new NullPointerException("ServiceReference of class" + serviceReference.getClass() + "not found."); } - StringBuffer errors = new StringBuffer(); + String moduleName = factory.getImplementationName(); if (moduleName == null || moduleName.isEmpty()) { throw new IllegalStateException( @@ -63,23 +63,17 @@ public class BundleContextBackedModuleFactoriesResolver implements throw new NullPointerException("Bundle context of " + factory + " ModuleFactory not found."); } logger.debug("Reading factory {} {}", moduleName, factory); - String error = null; + Map.Entry conflicting = result.get(moduleName); if (conflicting != null) { - error = String - .format("Module name is not unique. Found two conflicting factories with same name '%s': " + - "\n\t%s\n\t%s\n", moduleName, conflicting.getKey(), factory); - - } - - if (error == null) { + String error = String + .format("Module name is not unique. Found two conflicting factories with same name '%s': '%s' '%s'", + moduleName, conflicting.getKey(), factory); + logger.error(error); + throw new IllegalArgumentException(error); + } else { result.put(moduleName, new AbstractMap.SimpleImmutableEntry<>(factory, serviceReference.getBundle().getBundleContext())); - } else { - errors.append(error); - } - if (errors.length() > 0) { - throw new IllegalArgumentException(errors.toString()); } } return result; diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java index d464cb9006..02cc5ea1e4 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java @@ -41,7 +41,7 @@ public class ConfigManagerActivator implements BundleActivator { private RuntimeGeneratedMappingServiceActivator mappingServiceActivator; @Override - public void start(BundleContext context) throws Exception { + public void start(BundleContext context) { // track bundles containing YangModuleInfo ModuleInfoBundleTracker moduleInfoBundleTracker = new ModuleInfoBundleTracker(); @@ -72,7 +72,7 @@ public class ConfigManagerActivator implements BundleActivator { try { configRegistryJMXRegistrator.registerToJMX(configRegistry); } catch (InstanceAlreadyExistsException e) { - throw new RuntimeException("Config Registry was already registered to JMX", e); + throw new IllegalStateException("Config Registry was already registered to JMX", e); } ServiceTracker serviceTracker = new ServiceTracker<>(context, ModuleFactory.class, @@ -81,7 +81,7 @@ public class ConfigManagerActivator implements BundleActivator { } @Override - public void stop(BundleContext context) throws Exception { + public void stop(BundleContext context) { try { configRegistry.close(); } catch (Exception e) { 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/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/FtlFilePersister.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/FtlFilePersister.java index d6d3893beb..37d5e6bd3f 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/FtlFilePersister.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/FtlFilePersister.java @@ -53,7 +53,7 @@ public class FtlFilePersister { ftlFile.getFtlTempleteLocation()); try { template.process(ftlFile, writer); - } catch (Throwable e) { + } catch (Exception e) { throw new IllegalStateException( "Template error while generating " + ftlFile, e); } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java index 4a9d5512d3..676c8eca6e 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java @@ -195,16 +195,17 @@ final class ModuleMXBeanEntryBuilder { boolean providedServiceWasSet = false; for (UnknownSchemaNode unknownNode : id.getUnknownSchemaNodes()) { // TODO: test this - if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME.equals(unknownNode.getNodeType())) { - // no op: 0 or more provided identities are allowed - } else if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME.equals(unknownNode.getNodeType())) { + boolean unknownNodeIsProvidedServiceExtension = ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME.equals(unknownNode.getNodeType()); + // true => no op: 0 or more provided identities are allowed + + if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME.equals(unknownNode.getNodeType())) { // 0..1 allowed checkState( providedServiceWasSet == false, format("More than one language extension %s is not allowed here: %s", ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME, id)); providedServiceWasSet = true; - } else { + } else if (unknownNodeIsProvidedServiceExtension == false) { throw new IllegalStateException("Unexpected language extension " + unknownNode.getNodeType()); } } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java index 84300cb81d..cbeb5c3b29 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java @@ -25,7 +25,9 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; import javax.management.openmbean.OpenType; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -208,22 +210,20 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute { @Override public CompositeType getOpenType() { - String description = getNullableDescription() == null ? getAttributeYangName() - : getNullableDescription(); - final String[] itemNames = new String[yangNameToAttributeMap.keySet() - .size()]; - String[] itemDescriptions = itemNames; - FunctionImpl functionImpl = new FunctionImpl(itemNames); + String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription(); + + FunctionImpl functionImpl = new FunctionImpl(); Map jmxPropertiesToTypesMap = getJmxPropertiesToTypesMap(); OpenType[] itemTypes = Collections2.transform( jmxPropertiesToTypesMap.entrySet(), functionImpl).toArray( new OpenType[] {}); + String[] itemNames = functionImpl.getItemNames(); try { // TODO add package name to create fully qualified name for this // type CompositeType compositeType = new CompositeType( getUpperCaseCammelCase(), description, itemNames, - itemDescriptions, itemTypes); + itemNames, itemTypes); return compositeType; } catch (OpenDataException e) { throw new RuntimeException("Unable to create CompositeType for " @@ -235,20 +235,20 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute { return packageName; } - private static final class FunctionImpl implements - Function, OpenType> { - private final String[] itemNames; - int i = 0; +} - private FunctionImpl(String[] itemNames) { - this.itemNames = itemNames; - } +class FunctionImpl implements + Function, OpenType> { + private final List itemNames = new ArrayList<>(); - @Override - public OpenType apply(Entry input) { - AttributeIfc innerType = input.getValue(); - itemNames[i++] = input.getKey(); - return innerType.getOpenType(); - } + @Override + public OpenType apply(Entry input) { + AttributeIfc innerType = input.getValue(); + itemNames.add(input.getKey()); + return innerType.getOpenType(); + } + + public String[] getItemNames(){ + return itemNames.toArray(new String[itemNames.size()]); } } diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModule.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModule.java index b000f11e4e..398bba99bd 100644 --- a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModule.java +++ b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModule.java @@ -31,15 +31,16 @@ public final class IdentityTestModule extends org.opendaylight.controller.config @Override public java.lang.AutoCloseable createInstance() { - System.err.println(getAfi()); - System.err.println(getAfiIdentity()); + org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass()); + logger.info("Afi: {}", getAfi()); + logger.info("Afi class: {}", getAfiIdentity()); - getAfiIdentity(); for (Identities identities : getIdentities()) { - identities.resolveAfi(); - identities.resolveSafi(); + logger.info("Identities Afi class: {}", identities.resolveAfi()); + logger.info("Identities Safi class: {}", identities.resolveSafi()); + } - getIdentitiesContainer().resolveAfi(); + logger.info("IdentityContainer Afi class: {}", getIdentitiesContainer().resolveAfi()); return new AutoCloseable() { @Override diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModuleStub.txt b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModuleStub.txt index a81159ea24..7fa0c10eb2 100644 --- a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModuleStub.txt +++ b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModuleStub.txt @@ -1,12 +1,13 @@ - System.err.println(getAfi()); - System.err.println(getAfiIdentity()); + org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass()); + logger.info("Afi: {}", getAfi()); + logger.info("Afi class: {}", getAfiIdentity()); - getAfiIdentity(); for (Identities identities : getIdentities()) { - identities.resolveAfi(); - identities.resolveSafi(); + logger.info("Identities Afi class: {}", identities.resolveAfi()); + logger.info("Identities Safi class: {}", identities.resolveSafi()); + } - getIdentitiesContainer().resolveAfi(); + logger.info("IdentityContainer Afi class: {}", getIdentitiesContainer().resolveAfi()); return new AutoCloseable() { @Override diff --git a/opendaylight/distribution/opendaylight/src/main/resources/run.sh b/opendaylight/distribution/opendaylight/src/main/resources/run.sh index 90e3b03ae4..64f2c877f7 100755 --- a/opendaylight/distribution/opendaylight/src/main/resources/run.sh +++ b/opendaylight/distribution/opendaylight/src/main/resources/run.sh @@ -59,7 +59,7 @@ else fi function usage { - echo "Usage: $0 [-jmx] [-jmxport ] [-debug] [-debugsuspend] [-debugport ] [-start []] [-stop] [-status] [-console] [-help] []" + echo "Usage: $0 [-jmx] [-jmxport ] [-debug] [-debugsuspend] [-debugport ] [-start []] [-stop] [-status] [-console] [-help] [-agentpath:] []" exit 1 } @@ -83,6 +83,7 @@ statusdaemon=0 consolestart=1 dohelp=0 extraJVMOpts="" +agentPath="" unknown_option=0 while true ; do case "$1" in @@ -98,6 +99,7 @@ while true ; do -help) dohelp=1; shift;; -D*) extraJVMOpts="${extraJVMOpts} $1"; shift;; -X*) extraJVMOpts="${extraJVMOpts} $1"; shift;; + -agentpath:*) agentPath="$1"; shift;; "") break ;; *) echo "Unknown option $1"; unknown_option=1; shift ;; esac @@ -209,6 +211,7 @@ if [ "${startdaemon}" -eq 1 ]; then exit -1 fi $JAVA_HOME/bin/java ${extraJVMOpts} \ + ${agentPath} \ -Djava.io.tmpdir="${iotmpdir}/work/tmp" \ -Dosgi.install.area="${bdir}" \ -Dosgi.configuration.area="${confarea}/configuration" \ @@ -227,6 +230,7 @@ elif [ "${consolestart}" -eq 1 ]; then exit -1 fi $JAVA_HOME/bin/java ${extraJVMOpts} \ + ${agentPath} \ -Djava.io.tmpdir="${iotmpdir}/work/tmp" \ -Dosgi.install.area="${bdir}" \ -Dosgi.configuration.area="${confarea}/configuration" \ diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index e4190fbd7f..6cc06ba705 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -109,7 +109,7 @@ 1.9.5 - 2.4.3 + jacoco @@ -170,11 +170,7 @@ slf4j-api ${slf4j.version} - - org.eclipse.xtend - org.eclipse.xtend.lib - ${xtend.version} - + org.osgi org.osgi.core 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-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/WriteParentReadChildTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/WriteParentReadChildTest.java new file mode 100644 index 0000000000..35b4e92db4 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/WriteParentReadChildTest.java @@ -0,0 +1,113 @@ +/* + * 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.test.bugfix; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; + +import com.google.common.collect.ImmutableList; + +public class WriteParentReadChildTest extends AbstractDataServiceTest { + + private static final String FLOW_ID = "1234"; + private static final short TABLE_ID = (short) 0; + private static final String NODE_ID = "node:1"; + + private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID)); + private static final FlowKey FLOW_KEY = new FlowKey(new FlowId(FLOW_ID)); + private static final TableKey TABLE_KEY = new TableKey(TABLE_ID); + + private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) // + .child(Node.class, NODE_KEY).toInstance(); + + private static final InstanceIdentifier TABLE_INSTANCE_ID_BA = // + InstanceIdentifier.builder(NODE_INSTANCE_ID_BA) // + .augmentation(FlowCapableNode.class).child(Table.class, TABLE_KEY).build(); + + private static final InstanceIdentifier FLOW_INSTANCE_ID_BA = // + InstanceIdentifier.builder(TABLE_INSTANCE_ID_BA) // + .child(Flow.class, FLOW_KEY) // + .toInstance(); + /** + * + * The scenario tests writing parent node, which also contains child items + * and then reading child directly, by specifying path to the child. + * + * Expected behaviour is child is returned. + * + * @throws Exception + */ + @Test + public void writeTableReadFlow() throws Exception { + + DataModificationTransaction modification = baDataService.beginTransaction(); + + Flow flow = new FlowBuilder() // + .setKey(FLOW_KEY) // + .setMatch(new MatchBuilder() // + .setVlanMatch(new VlanMatchBuilder() // + .setVlanId(new VlanIdBuilder() // + .setVlanId(new VlanId(10)) // + .build()) // + .build()) // + .build()) // + .setInstructions(new InstructionsBuilder() // + .setInstruction(ImmutableList.builder() // + .build()) // + .build()) // + .build(); + + Table table = new TableBuilder() + .setKey(TABLE_KEY) + .setFlow(ImmutableList.of(flow)) + .build(); + + modification.putConfigurationData(TABLE_INSTANCE_ID_BA, table); + RpcResult ret = modification.commit().get(); + assertNotNull(ret); + assertEquals(TransactionStatus.COMMITED, ret.getResult()); + + DataObject readedTable = baDataService.readConfigurationData(TABLE_INSTANCE_ID_BA); + assertNotNull("Readed table should not be nul.", readedTable); + assertTrue(readedTable instanceof Table); + + DataObject readedFlow = baDataService.readConfigurationData(FLOW_INSTANCE_ID_BA); + assertNotNull("Readed flow should not be null.",readedFlow); + assertTrue(readedFlow instanceof Flow); + assertEquals(flow, readedFlow); + + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-it/pom.xml b/opendaylight/md-sal/sal-binding-it/pom.xml index 9bc8a48214..213e4f47f7 100644 --- a/opendaylight/md-sal/sal-binding-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-it/pom.xml @@ -132,32 +132,33 @@ + + + + org.opendaylight.yangtools.thirdparty xtend-lib-osgi 2.4.3 - test org.opendaylight.controller sal-binding-broker-impl - provided org.ops4j.pax.exam pax-exam-container-native - test + compile org.ops4j.pax.exam pax-exam-junit4 - test + compile org.opendaylight.controller config-netconf-connector - test org.opendaylight.controller @@ -207,12 +208,11 @@ org.ops4j.pax.exam pax-exam-link-mvn - test + compile equinoxSDK381 org.eclipse.osgi - test org.slf4j @@ -229,7 +229,6 @@ org.mockito mockito-all - test org.opendaylight.controller.model 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/Broker.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Broker.java index f7c46086e3..6af06255c7 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Broker.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Broker.java @@ -25,16 +25,16 @@ import org.osgi.framework.BundleContext; /** * Core component of the SAL layer responsible for wiring the SAL consumers. - * + * * The responsibility of the broker is to maintain registration of SAL * functionality {@link Consumer}s and {@link Provider}s, store provider and * consumer specific context and functionality registration via * {@link ConsumerSession} and provide access to infrastructure services, which * removes direct dependencies between providers and consumers. - * - * + * + * *

Infrastructure services

Some examples of infrastructure services: - * + * *
    *
  • RPC Invocation - see {@link ConsumerSession#rpc(QName, CompositeNode)}, * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)} and @@ -45,41 +45,41 @@ import org.osgi.framework.BundleContext; *
  • Data Store access and modification - see {@link DataBrokerService} and * {@link DataProviderService} *
- * + * * The services are exposed via session. - * + * *

Session-based access

- * + * * The providers and consumers needs to register in order to use the * binding-independent SAL layer and to expose functionality via SAL layer. - * + * * For more information about session-based access see {@link ConsumerSession} * and {@link ProviderSession} - * - * - * + * + * + * */ public interface Broker { /** * Registers the {@link Consumer}, which will use the SAL layer. - * + * *

* During the registration, the broker obtains the initial functionality * from consumer, using the {@link Consumer#getConsumerFunctionality()}, and * register that functionality into system and concrete infrastructure * services. - * + * *

* Note that consumer could register additional functionality at later point * by using service and functionality specific APIs. - * + * *

* The consumer is required to use returned session for all communication * with broker or one of the broker services. The session is announced to * the consumer by invoking * {@link Consumer#onSessionInitiated(ConsumerSession)}. - * + * * @param cons * Consumer to be registered. * @param context @@ -93,25 +93,25 @@ public interface Broker { /** * Registers the {@link Provider}, which will use the SAL layer. - * + * *

* During the registration, the broker obtains the initial functionality * from consumer, using the {@link Provider#getProviderFunctionality()}, and * register that functionality into system and concrete infrastructure * services. - * + * *

* Note that consumer could register additional functionality at later point * by using service and functionality specific APIs (e.g. * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)} - * + * *

* The consumer is required to use returned session for all * communication with broker or one of the broker services. The session is * announced to the consumer by invoking * {@link Provider#onSessionInitiated(ProviderSession)}. - * - * + * + * * @param prov * Provider to be registered. * @param context @@ -125,25 +125,25 @@ public interface Broker { /** * {@link Consumer} specific access to the SAL functionality. - * + * *

* ConsumerSession is {@link Consumer}-specific access to the SAL * functionality and infrastructure services. - * + * *

* The session serves to store SAL context (e.g. registration of * functionality) for the consumer and provides access to the SAL * infrastructure services and other functionality provided by * {@link Provider}s. - * - * - * + * + * + * */ public interface ConsumerSession { /** * Sends an RPC to other components registered to the broker. - * + * * @see RpcImplementation * @param rpc * Name of RPC @@ -158,7 +158,7 @@ public interface Broker { /** * Returns a session specific instance (implementation) of requested * service - * + * * @param service * Broker service * @return Session specific implementation of service @@ -167,44 +167,44 @@ public interface Broker { /** * Closes a session between consumer and broker. - * + * *

* The close operation unregisters a consumer and remove all registered * functionality of the consumer from the system. - * + * */ void close(); } /** * {@link Provider} specific access to the SAL functionality. - * + * *

* ProviderSession is {@link Provider}-specific access to the SAL * functionality and infrastructure services, which also allows for exposing * the provider's functionality to the other {@link Consumer}s. - * + * *

* The session serves to store SAL context (e.g. registration of * functionality) for the providers and exposes access to the SAL * infrastructure services, dynamic functionality registration and any other * functionality provided by other {@link Provider}s. - * + * */ public interface ProviderSession extends ConsumerSession { /** * Registers an implementation of the rpc. - * + * *

* The registered rpc functionality will be available to all other * consumers and providers registered to the broker, which are aware of * the {@link QName} assigned to the rpc. - * + * *

* There is no assumption that rpc type is in the set returned by * invoking {@link RpcImplementation#getSupportedRpcs()}. This allows * for dynamic rpc implementations. - * + * * @param rpcType * Name of Rpc * @param implementation @@ -221,7 +221,7 @@ public interface Broker { /** * Closes a session between provider and SAL. - * + * *

* The close operation unregisters a provider and remove all registered * functionality of the provider from the system. @@ -233,12 +233,15 @@ public interface Broker { boolean isClosed(); Set getSupportedRpcs(); - + ListenerRegistration addRpcRegistrationListener(RpcRegistrationListener listener); } public interface RpcRegistration extends Registration { QName getType(); + + @Override + void close(); } public interface RoutedRpcRegistration extends RpcRegistration, 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 602afd7c0c..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 @@ -9,11 +9,19 @@ package org.opendaylight.controller.sal.dom.broker.impl; import static com.google.common.base.Preconditions.checkState; +import java.io.Console; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.Future; +import javax.activation.UnsupportedDataTypeException; + import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataModification; import org.opendaylight.controller.md.sal.common.api.data.DataReader; @@ -26,22 +34,26 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder; import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.api.SimpleNode; import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; +import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; 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.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableSet; public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator implements // DataStore, // - SchemaServiceListener, // SchemaContextListener, // AutoCloseable { @@ -169,10 +181,10 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator original) { NormalizedDataModification normalized = new NormalizedDataModification(original); for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { - normalized.putConfigurationData(entry.getKey(), entry.getValue()); + normalized.putDeepConfigurationData(entry.getKey(), entry.getValue()); } for (Entry entry : original.getUpdatedOperationalData().entrySet()) { - normalized.putOperationalData(entry.getKey(), entry.getValue()); + normalized.putDeepOperationalData(entry.getKey(), entry.getValue()); } for (InstanceIdentifier entry : original.getRemovedConfigurationData()) { normalized.deepRemoveConfigurationData(entry); @@ -310,6 +322,8 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator { + private final String CONFIGURATIONAL_DATA_STORE_MARKER = "configurational"; + private final String OPERATIONAL_DATA_STORE_MARKER = "operational"; private final Object identifier; private TransactionStatus status; @@ -342,6 +356,14 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator child : entryData.getChildren()) { + InstanceIdentifier subEntryId = InstanceIdentifier.builder(entryKey).node(child.getNodeType()).toInstance(); + if (child instanceof CompositeNode) { + DataSchemaNode subSchema = schemaNodeFor(subEntryId); + CompositeNode compNode = (CompositeNode) child; + InstanceIdentifier instanceId = null; + + if (subSchema instanceof ListSchemaNode) { + ListSchemaNode listSubSchema = (ListSchemaNode) subSchema; + Map mapOfSubValues = this.getValuesFromListSchema(listSubSchema, (CompositeNode) child); + if (mapOfSubValues != null) { + instanceId = InstanceIdentifier.builder(entryKey).nodeWithKey(listSubSchema.getQName(), mapOfSubValues).toInstance(); + } + } + else if (subSchema instanceof ContainerSchemaNode) { + ContainerSchemaNode containerSchema = (ContainerSchemaNode) subSchema; + instanceId = InstanceIdentifier.builder(entryKey).node(subSchema.getQName()).toInstance(); + } + if (instanceId != null) { + this.putCompositeNodeData(instanceId, compNode, dataStoreIdentifier); + } + } + } + } + + private Map getValuesFromListSchema (ListSchemaNode listSchema, CompositeNode entryData) { + List keyDef = listSchema.getKeyDefinition(); + if (keyDef != null && ! keyDef.isEmpty()) { + Map map = new HashMap(); + for (QName key : keyDef) { + List> data = entryData.get(key); + if (data != null && ! data.isEmpty()) { + for (Node nodeData : data) { + if (nodeData instanceof SimpleNode) { + map.put(key, data.get(0).getValue()); + } + } + } + } + return map; + } + return null; + } + } } 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/client/SalRemoteClient.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClient.java new file mode 100644 index 0000000000..0044d367f8 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClient.java @@ -0,0 +1,16 @@ +/* + * 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.restconf.broker.client; + +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; + +public interface SalRemoteClient extends AutoCloseable { + + ConsumerContext registerConsumer(); + +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClientDeployer.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClientDeployer.java new file mode 100644 index 0000000000..a1bb81b0bb --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClientDeployer.java @@ -0,0 +1,18 @@ +/* + * 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.restconf.broker.client; + +import java.net.URL; + +public class SalRemoteClientDeployer { + + public static SalRemoteClient createSalRemoteClient(final URL url) { + return new SalRemoteClientImpl(url); + } + +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClientImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClientImpl.java new file mode 100644 index 0000000000..ec62568a1b --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClientImpl.java @@ -0,0 +1,76 @@ +/* + * 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.restconf.broker.client; + +import java.net.URL; + +import javassist.ClassPool; + +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; +import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; +import org.opendaylight.controller.sal.restconf.broker.SalRemoteServiceBroker; +import org.opendaylight.yangtools.restconf.client.RestconfClientFactory; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; +import org.opendaylight.yangtools.restconf.client.api.UnsupportedProtocolException; +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; +import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.util.BindingReflections; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +class SalRemoteClientImpl implements SalRemoteClient { + + private static final Logger logger = LoggerFactory.getLogger(SalRemoteClientImpl.class); + + private final RestconfClientContext restconfClientContext; + private final SalRemoteServiceBroker salRemoteBroker; + private final RuntimeGeneratedMappingServiceImpl mappingService; + + public SalRemoteClientImpl(final URL url) { + Preconditions.checkNotNull(url); + + this.mappingService = new RuntimeGeneratedMappingServiceImpl(); + this.mappingService.setPool(ClassPool.getDefault()); + this.mappingService.init(); + + final ModuleInfoBackedContext moduleInfo = ModuleInfoBackedContext.create(); + moduleInfo.addModuleInfos(BindingReflections.loadModuleInfos()); + this.mappingService.onGlobalContextUpdated(moduleInfo.tryToCreateSchemaContext().get()); + + try { + this.restconfClientContext = new RestconfClientFactory().getRestconfClientContext(url, this.mappingService, + this.mappingService); + + this.salRemoteBroker = new SalRemoteServiceBroker("remote-broker", restconfClientContext); + this.salRemoteBroker.start(); + } catch (UnsupportedProtocolException e) { + logger.error("Unsupported protocol {}.", url.getProtocol(), e); + throw new IllegalArgumentException("Unsupported protocol.", e); + } + } + + @Override + public ConsumerContext registerConsumer() { + return this.salRemoteBroker.registerConsumer(new BindingAwareConsumer() { + + @Override + public void onSessionInitialized(ConsumerContext session) { + } + }, null); + } + + @Override + public void close() throws Exception { + this.restconfClientContext.close(); + this.salRemoteBroker.close(); + } + +} 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 9410d17007..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; @@ -22,12 +21,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controll import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService; +import org.opendaylight.yangtools.concepts.AbstractListenerRegistration; import org.opendaylight.yangtools.concepts.ListenerRegistration; 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; @@ -45,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() { @@ -93,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 { @@ -149,22 +99,12 @@ public class DataBrokerServiceImpl implements DataBrokerService { final Map desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext,streamName); ListenableEventStreamContext restConfListenableEventStreamContext = restconfClientContext.getEventStreamContext(desiredEventStream.get(streamName)); RemoteDataChangeNotificationListener remoteDataChangeNotificationListener = new RemoteDataChangeNotificationListener(listener); - restConfListenableEventStreamContext.registerNotificationListener(remoteDataChangeNotificationListener); - return new SalRemoteDataListenerRegistration(listener); - } - - private class SalRemoteDataListenerRegistration implements ListenerRegistration { - private final DataChangeListener dataChangeListener; - public SalRemoteDataListenerRegistration(DataChangeListener dataChangeListener){ - this.dataChangeListener = dataChangeListener; - } - @Override - public DataChangeListener getInstance() { - return this.dataChangeListener; - } - @Override - public void close() { - //noop - } + final ListenerRegistration reg = restConfListenableEventStreamContext.registerNotificationListener(remoteDataChangeNotificationListener); + return new AbstractListenerRegistration(listener) { + @Override + protected void removeRegistration() { + reg.close(); + } + }; } } 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-it/pom.xml b/opendaylight/netconf/netconf-it/pom.xml index 549d4074eb..57067f47ec 100644 --- a/opendaylight/netconf/netconf-it/pom.xml +++ b/opendaylight/netconf/netconf-it/pom.xml @@ -28,11 +28,6 @@ yang-store-api test - - ${project.groupId} - yang-test - test - ${project.groupId} netconf-api @@ -74,6 +69,12 @@ netconf-monitoring test + + ${project.groupId} + sal-binding-it + ${mdsal.version} + test + ${project.groupId} netconf-mapping-api @@ -96,6 +97,12 @@ test test-jar + + org.opendaylight.controller + yang-test + ${config.version} + test + ${project.groupId} yang-store-impl @@ -155,6 +162,19 @@ + + org.ops4j.pax.exam + maven-paxexam-plugin + 1.2.4 + + + generate-config + + generate-depends-file + + + + diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/pax/IdentityRefNetconfTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/pax/IdentityRefNetconfTest.java new file mode 100644 index 0000000000..4e536c43bd --- /dev/null +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/pax/IdentityRefNetconfTest.java @@ -0,0 +1,138 @@ +/* + * 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.it.pax; + +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.baseModelBundles; +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.bindingAwareSalBundles; +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.configMinumumBundles; +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.flowCapableModelBundles; +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.junitAndMockitoBundles; +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.mdSalCoreBundles; +import static org.ops4j.pax.exam.CoreOptions.mavenBundle; +import static org.ops4j.pax.exam.CoreOptions.options; +import static org.ops4j.pax.exam.CoreOptions.systemProperty; + +import javax.inject.Inject; +import javax.xml.parsers.ParserConfigurationException; + +import com.google.common.base.Preconditions; +import io.netty.channel.nio.NioEventLoopGroup; +import org.junit.Assert; +import org.junit.Test; +import org.junit.matchers.JUnitMatchers; +import org.junit.runner.RunWith; +import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.controller.netconf.client.NetconfClient; +import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.options.DefaultCompositeOption; +import org.ops4j.pax.exam.util.Filter; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +@RunWith(PaxExam.class) +public class IdentityRefNetconfTest { + + public static final int CLIENT_CONNECTION_TIMEOUT_MILLIS = 5000; + + // Wait for controller to start + @Inject + @Filter(timeout = 60 * 1000) + BindingAwareBroker broker; + + @Configuration + public Option[] config() { + return options( + systemProperty("osgi.console").value("2401"), + systemProperty("osgi.bundles.defaultStartLevel").value("4"), + systemProperty("pax.exam.osgi.unresolved.fail").value("true"), + + testingModules(), + loggingModules(), + mdSalCoreBundles(), + bindingAwareSalBundles(), configMinumumBundles(), baseModelBundles(), flowCapableModelBundles(), + junitAndMockitoBundles()); + } + + private Option loggingModules() { + return new DefaultCompositeOption( + mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), + mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), + mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), + mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject()); + } + + private Option testingModules() { + return new DefaultCompositeOption( + mavenBundle("org.opendaylight.controller", "yang-test").versionAsInProject()); + } + + private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 18383); + + @Test + public void testIdRef() throws Exception { + Preconditions.checkNotNull(broker, "Controller not initialized"); + + NioEventLoopGroup nettyThreadgroup = new NioEventLoopGroup(); + NetconfClientDispatcher clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, + CLIENT_CONNECTION_TIMEOUT_MILLIS); + + NetconfMessage edit = xmlFileToNetconfMessage("netconfMessages/editConfig_identities.xml"); + NetconfMessage commit = xmlFileToNetconfMessage("netconfMessages/commit.xml"); + NetconfMessage getConfig = xmlFileToNetconfMessage("netconfMessages/getConfig.xml"); + + try (NetconfClient netconfClient = new NetconfClient("client", tcpAddress, CLIENT_CONNECTION_TIMEOUT_MILLIS, clientDispatcher)) { + sendMessage(edit, netconfClient); + sendMessage(commit, netconfClient); + sendMessage(getConfig, netconfClient, "id-test", + "prefix:test-identity1", + "prefix:test-identity2", + "prefix:test-identity2", + "prefix:test-identity1"); + } + + clientDispatcher.close(); + } + + private void sendMessage(NetconfMessage edit, NetconfClient netconfClient, String... containingResponse) + throws ExecutionException, InterruptedException, TimeoutException { + NetconfMessage response = netconfClient.sendRequest(edit).get(); + if (containingResponse == null) { + Assert.assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("")); + } else { + for (String resp : containingResponse) { + Assert.assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString(resp)); + } + } + } + + public static NetconfMessage xmlFileToNetconfMessage(final String fileName) throws IOException, SAXException, + ParserConfigurationException { + return new NetconfMessage(xmlFileToDocument(fileName)); + } + + public static Document xmlFileToDocument(final String fileName) throws IOException, SAXException, + ParserConfigurationException { + // TODO xml messages from netconf-util test-jar cannot be loaded here(in OSGi), since test jar is not a bundle + try (InputStream resourceAsStream = IdentityRefNetconfTest.class.getClassLoader().getResourceAsStream(fileName)) { + Preconditions.checkNotNull(resourceAsStream); + final Document doc = XmlUtil.readXmlToDocument(resourceAsStream); + return doc; + } + } +} diff --git a/opendaylight/netconf/netconf-it/src/test/resources/controller.xml b/opendaylight/netconf/netconf-it/src/test/resources/controller.xml new file mode 100644 index 0000000000..664a30daa5 --- /dev/null +++ b/opendaylight/netconf/netconf-it/src/test/resources/controller.xml @@ -0,0 +1,181 @@ + + + + + + urn:opendaylight:params:xml:ns:yang:controller:config:test:types?module=test-types&revision=2013-11-27 + urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05 + urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16 + urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28 + urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 + urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28 + urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28 + urn:opendaylight:params:xml:ns:yang:controller:test:impl?module=config-test-impl&revision=2013-04-03 + urn:opendaylight:params:xml:ns:yang:controller:test?module=config-test&revision=2013-06-13 + + + + + + prefix:impl-identity-test + id-test + + prefix:test-identity2 + + + prefix:test-identity2 + prefix:test-identity1 + + + prefix:test-identity1 + prefix:test-identity2 + + prefix:test-identity1 + + + prefix:binding-broker-impl + binding-broker-impl + + prefix:binding-notification-service + ref_binding-notification-broker + + + prefix:binding-data-broker + ref_binding-data-broker + + + + prefix:runtime-generated-mapping + runtime-mapping-singleton + + + prefix:binding-notification-broker + binding-notification-broker + + + prefix:binding-data-broker + binding-data-broker + + prefix:dom-broker-osgi-registry + ref_dom-broker + + + prefix:binding-dom-mapping-service + ref_runtime-mapping-singleton + + + + prefix:logback + singleton + + DEBUG + console + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + DEBUG + ROOT + console + + + + prefix:schema-service-singleton + yang-schema-service + + + prefix:hash-map-data-store + hash-map-data-store + + + prefix:dom-broker-impl + dom-broker + + prefix:dom-data-store + ref_hash-map-data-store + + + + + + prefix:schema-service + + ref_yang-schema-service + /modules/module[type='schema-service-singleton'][name='yang-schema-service'] + + + + prefix:dom-data-store + + ref_hash-map-data-store + /modules/module[type='hash-map-data-store'][name='hash-map-data-store'] + + + + prefix:dom-broker-osgi-registry + + ref_dom-broker + /modules/module[type='dom-broker-impl'][name='dom-broker'] + + + + prefix:testing + + ref_id-test + /modules/module[type='impl-identity-test'][name='id-test'] + + + + prefix:binding-dom-mapping-service + + ref_runtime-mapping-singleton + /modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton'] + + + + prefix:binding-data-consumer-broker + + ref_binding-data-broker + /modules/module[type='binding-data-broker'][name='binding-data-broker'] + + + + prefix:binding-rpc-registry + + ref_binding-broker-impl + /modules/module[type='binding-broker-impl'][name='binding-broker-impl'] + + + + prefix:binding-notification-service + + ref_binding-notification-broker + /modules/module[type='binding-notification-broker'][name='binding-notification-broker'] + + + + prefix:binding-broker-osgi-registry + + ref_binding-broker-impl + /modules/module[type='binding-broker-impl'][name='binding-broker-impl'] + + + + prefix:binding-notification-subscription-service + + ref_binding-notification-broker + /modules/module[type='binding-notification-broker'][name='binding-notification-broker'] + + + + prefix:binding-data-broker + + ref_binding-data-broker + /modules/module[type='binding-data-broker'][name='binding-data-broker'] + + + + + + + + diff --git a/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/commit.xml b/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/commit.xml new file mode 100644 index 0000000000..ffdf132153 --- /dev/null +++ b/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/commit.xml @@ -0,0 +1,3 @@ + + + diff --git a/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/editConfig_identities.xml b/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/editConfig_identities.xml new file mode 100644 index 0000000000..cf9f3e5ccd --- /dev/null +++ b/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/editConfig_identities.xml @@ -0,0 +1,37 @@ + + + + + + + set + + merge + + + + + test-impl:impl-identity-test + + id-test + + prefix:test-identity1 + prefix:test-identity2 + + + prefix:test-identity2 + prefix:test-identity1 + + + prefix:test-identity2 + + prefix:test-identity1 + + + + + + + + + diff --git a/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/getConfig.xml b/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/getConfig.xml new file mode 100644 index 0000000000..39efb4961b --- /dev/null +++ b/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/getConfig.xml @@ -0,0 +1,7 @@ + + + + + + + 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();