From: Tony Tkacik Date: Thu, 27 Feb 2014 16:06:03 +0000 (+0000) Subject: Merge "Exception for URI /restconf/operations/module_name:rpc ended with slash" X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~370 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=4eb724db3877173d502ba38c6d83bec780b38bb2;hp=a812fd97808299ed90e388e83c469d5f3d8348c3 Merge "Exception for URI /restconf/operations/module_name:rpc ended with slash" --- diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index 328dfafe3f..d42f1fd83d 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -77,14 +77,14 @@ 0.5.2-SNAPSHOT 0.5.2-SNAPSHOT 0.5.2-SNAPSHOT - 0.2.4-SNAPSHOT - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT + 0.2.5-SNAPSHOT 1.1-SNAPSHOT 0.5.2-SNAPSHOT 0.5.2-SNAPSHOT 0.7.1-SNAPSHOT 0.1.2-SNAPSHOT - 0.7.1-SNAPSHOT + 0.8.1-SNAPSHOT 0.0.3-SNAPSHOT 0.1.2-SNAPSHOT 0.0.3-SNAPSHOT @@ -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} - @@ -1804,6 +1801,11 @@ maven-release-plugin ${releaseplugin.version} + + org.opendaylight.yangtools + yang-maven-plugin + ${yangtools.version} + org.eclipse.m2e @@ -1991,6 +1993,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 config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT config-api diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConflictingVersionException.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConflictingVersionException.java index 9c25242c2d..2edf261499 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConflictingVersionException.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConflictingVersionException.java @@ -14,7 +14,7 @@ package org.opendaylight.controller.config.api; * transaction was committed after creating this transaction. Clients can create * new transaction and merge the changes. */ -public class ConflictingVersionException extends RuntimeException { +public class ConflictingVersionException extends Exception { private static final long serialVersionUID = 1L; public ConflictingVersionException() { diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/IdentityAttributeRef.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/IdentityAttributeRef.java index 73737593cf..5ad6e0da8d 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/IdentityAttributeRef.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/IdentityAttributeRef.java @@ -19,8 +19,9 @@ public final class IdentityAttributeRef { @ConstructorProperties(QNAME_ATTR_NAME) public IdentityAttributeRef(String qNameOfIdentity) { - if (qNameOfIdentity == null) + if (qNameOfIdentity == null) { throw new NullPointerException("Parameter " + QNAME_ATTR_NAME + " is null"); + } this.qNameOfIdentity = qNameOfIdentity; } @@ -46,12 +47,18 @@ public final class IdentityAttributeRef { @Override public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof IdentityAttributeRef)) return false; + if (this == o) { + return true; + } + if (!(o instanceof IdentityAttributeRef)) { + return false; + } IdentityAttributeRef that = (IdentityAttributeRef) o; - if (!qNameOfIdentity.equals(that.qNameOfIdentity)) return false; + if (!qNameOfIdentity.equals(that.qNameOfIdentity)) { + return false; + } return true; } diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/JmxAttribute.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/JmxAttribute.java index 96deb051ef..244f22f58e 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/JmxAttribute.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/JmxAttribute.java @@ -15,8 +15,9 @@ public class JmxAttribute { private final String attributeName; public JmxAttribute(String attributeName) { - if (attributeName == null) + if (attributeName == null) { throw new NullPointerException("Parameter 'attributeName' is null"); + } this.attributeName = attributeName; } @@ -26,16 +27,19 @@ public class JmxAttribute { @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; + } JmxAttribute that = (JmxAttribute) o; if (attributeName != null ? !attributeName.equals(that.attributeName) - : that.attributeName != null) + : that.attributeName != null) { return false; + } return true; } diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ModuleIdentifier.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ModuleIdentifier.java index c654f5fe0a..7baaf9f6e4 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ModuleIdentifier.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ModuleIdentifier.java @@ -14,12 +14,12 @@ public class ModuleIdentifier implements Identifier { private final String factoryName, instanceName; public ModuleIdentifier(String factoryName, String instanceName) { - if (factoryName == null) - throw new IllegalArgumentException( - "Parameter 'factoryName' is null"); - if (instanceName == null) - throw new IllegalArgumentException( - "Parameter 'instanceName' is null"); + if (factoryName == null) { + throw new IllegalArgumentException("Parameter 'factoryName' is null"); + } + if (instanceName == null) { + throw new IllegalArgumentException("Parameter 'instanceName' is null"); + } this.factoryName = factoryName; this.instanceName = instanceName; } @@ -34,17 +34,21 @@ public class ModuleIdentifier 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; + } ModuleIdentifier that = (ModuleIdentifier) o; - if (!factoryName.equals(that.factoryName)) + if (!factoryName.equals(that.factoryName)) { return false; - if (!instanceName.equals(that.instanceName)) + } + if (!instanceName.equals(that.instanceName)) { return false; + } return true; } diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ValidationException.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ValidationException.java index f27d123995..82b73d419e 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ValidationException.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ValidationException.java @@ -16,9 +16,11 @@ import java.util.Map.Entry; /** * This exception is not intended to be used while implementing modules, - * itaggregates validation exceptions and sends them back to the user. + * it aggregates validation exceptions and sends them back to the user. + * Use {@link org.opendaylight.controller.config.api.JmxAttributeValidationException} for + * validating modules instead. */ -public class ValidationException extends RuntimeException { +public class ValidationException extends Exception { private static final long serialVersionUID = -6072893219820274247L; private final Map> failedValidations; @@ -118,23 +120,30 @@ public class ValidationException extends RuntimeException { @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; + } ExceptionMessageWithStackTrace other = (ExceptionMessageWithStackTrace) obj; if (message == null) { - if (other.message != null) + if (other.message != null) { return false; - } else if (!message.equals(other.message)) + } + } else if (!message.equals(other.message)) { return false; + } if (stackTrace == null) { - if (other.stackTrace != null) + if (other.stackTrace != null) { return false; - } else if (!stackTrace.equals(other.stackTrace)) + } + } else if (!stackTrace.equals(other.stackTrace)) { return false; + } return true; } diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/CommitStatus.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/CommitStatus.java index bd53bd4e58..4f9ea7ac6b 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/CommitStatus.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/CommitStatus.java @@ -7,32 +7,27 @@ */ package org.opendaylight.controller.config.api.jmx; +import javax.annotation.concurrent.Immutable; +import javax.management.ObjectName; import java.beans.ConstructorProperties; import java.util.Collections; import java.util.List; -import javax.annotation.concurrent.Immutable; -import javax.management.ObjectName; - @Immutable public class CommitStatus { private final List 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 524cd1ff9e..7d7d9d697a 100644 --- a/opendaylight/config/config-manager/pom.xml +++ b/opendaylight/config/config-manager/pom.xml @@ -3,7 +3,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT .. config-manager @@ -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/dynamicmbean/DynamicWritableWrapper.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java index 2ab04e53e3..335acc81fe 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java @@ -164,8 +164,9 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper { try { validate(); } catch (Exception e) { - throw ValidationException.createForSingleException( - moduleIdentifier, e); + + throw new MBeanException(ValidationException.createForSingleException( + moduleIdentifier, e)); } return Void.TYPE; } 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/BlankTransactionServiceTracker.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java index b973b92721..720b7197ea 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.config.manager.impl.osgi; import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.jmx.CommitStatus; import org.opendaylight.controller.config.manager.impl.ConfigRegistryImpl; import org.opendaylight.controller.config.spi.ModuleFactory; @@ -41,7 +42,8 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer< synchronized void blankTransaction() { // race condition check: config-persister might push new configuration while server is starting up. ConflictingVersionException lastException = null; - for (int i = 0; i < 10; i++) { + int maxAttempts = 10; + for (int i = 0; i < maxAttempts; i++) { try { // create transaction boolean blankTransaction = true; @@ -57,9 +59,13 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer< Thread.currentThread().interrupt(); throw new IllegalStateException(interruptedException); } + } catch (ValidationException e) { + logger.error("Validation exception while running blank transaction indicates programming error", e); + throw new RuntimeException("Validation exception while running blank transaction indicates programming error", e); } } - throw lastException; + throw new RuntimeException("Maximal number of attempts reached and still cannot get optimistic lock from " + + "config manager",lastException); } @Override 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 441de36db0..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 @@ -30,7 +30,6 @@ import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.ObjectName; import javax.management.ReflectionException; -import javax.management.RuntimeMBeanException; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -135,7 +134,7 @@ public class SimpleConfigurationTest extends AbstractConfigTest { private void testValidation(ConfigTransactionClient transaction) throws InstanceAlreadyExistsException, ReflectionException, - InstanceNotFoundException, MBeanException { + InstanceNotFoundException, MBeanException, ConflictingVersionException { ObjectName fixed1names = transaction.createModule( TestingFixedThreadPoolModuleFactory.NAME, fixed1); // call validate on config bean @@ -143,8 +142,8 @@ public class SimpleConfigurationTest extends AbstractConfigTest { platformMBeanServer.invoke(fixed1names, "validate", new Object[0], new String[0]); fail(); - } catch (RuntimeMBeanException e) { - RuntimeException targetException = e.getTargetException(); + } catch (MBeanException e) { + Exception targetException = e.getTargetException(); assertNotNull(targetException); assertEquals(ValidationException.class, targetException.getClass()); } @@ -327,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()); @@ -337,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/config-module-archetype/pom.xml b/opendaylight/config/config-module-archetype/pom.xml index 42c9105c05..7fb622460f 100644 --- a/opendaylight/config/config-module-archetype/pom.xml +++ b/opendaylight/config/config-module-archetype/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-subsystem - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT config-module-archetype diff --git a/opendaylight/config/config-persister-api/pom.xml b/opendaylight/config/config-persister-api/pom.xml index 403ee82b8e..f800e36985 100644 --- a/opendaylight/config/config-persister-api/pom.xml +++ b/opendaylight/config/config-persister-api/pom.xml @@ -3,7 +3,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT .. config-persister-api diff --git a/opendaylight/config/config-persister-directory-adapter/pom.xml b/opendaylight/config/config-persister-directory-adapter/pom.xml index 919fd13fc2..86b8c4d947 100644 --- a/opendaylight/config/config-persister-directory-adapter/pom.xml +++ b/opendaylight/config/config-persister-directory-adapter/pom.xml @@ -4,7 +4,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT .. config-persister-directory-adapter diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml b/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml index 92f7e27788..5e556c07a9 100644 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml +++ b/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml @@ -4,7 +4,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT .. config-persister-directory-autodetect-adapter diff --git a/opendaylight/config/config-persister-directory-xml-adapter/pom.xml b/opendaylight/config/config-persister-directory-xml-adapter/pom.xml index 2c5d2359a0..75188fe9b3 100644 --- a/opendaylight/config/config-persister-directory-xml-adapter/pom.xml +++ b/opendaylight/config/config-persister-directory-xml-adapter/pom.xml @@ -4,7 +4,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT .. config-persister-directory-xml-adapter diff --git a/opendaylight/config/config-persister-file-adapter/pom.xml b/opendaylight/config/config-persister-file-adapter/pom.xml index 4681b3b710..a8ea93e71b 100644 --- a/opendaylight/config/config-persister-file-adapter/pom.xml +++ b/opendaylight/config/config-persister-file-adapter/pom.xml @@ -4,7 +4,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT .. config-persister-file-adapter diff --git a/opendaylight/config/config-persister-file-xml-adapter/pom.xml b/opendaylight/config/config-persister-file-xml-adapter/pom.xml index 6fa496d92e..dd2079550e 100644 --- a/opendaylight/config/config-persister-file-xml-adapter/pom.xml +++ b/opendaylight/config/config-persister-file-xml-adapter/pom.xml @@ -4,7 +4,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT .. config-persister-file-xml-adapter diff --git a/opendaylight/config/config-plugin-parent/pom.xml b/opendaylight/config/config-plugin-parent/pom.xml index 0bc1ef6e76..e382c33871 100644 --- a/opendaylight/config/config-plugin-parent/pom.xml +++ b/opendaylight/config/config-plugin-parent/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-subsystem - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT 4.0.0 config-plugin-parent @@ -16,7 +16,6 @@ ${project.build.directory}/generated-sources/config - 0.2.4-SNAPSHOT diff --git a/opendaylight/config/config-util/pom.xml b/opendaylight/config/config-util/pom.xml index 6a50ee843a..9b866efb13 100644 --- a/opendaylight/config/config-util/pom.xml +++ b/opendaylight/config/config-util/pom.xml @@ -3,7 +3,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT .. config-util diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java index 3583dafd0d..4adc0d9364 100644 --- a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java +++ b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java @@ -7,24 +7,23 @@ */ package org.opendaylight.controller.config.util; -import java.util.Map; -import java.util.Set; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; +import org.opendaylight.controller.config.api.jmx.CommitStatus; +import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean; +import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import javax.management.Attribute; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.JMException; import javax.management.JMX; +import javax.management.MBeanException; import javax.management.MBeanServer; import javax.management.ObjectName; -import javax.management.RuntimeMBeanException; - -import org.opendaylight.controller.config.api.ConflictingVersionException; -import org.opendaylight.controller.config.api.ValidationException; -import org.opendaylight.controller.config.api.jmx.CommitStatus; -import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean; -import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean; -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import java.util.Map; +import java.util.Set; public class ConfigTransactionJMXClient implements ConfigTransactionClient { private final ConfigRegistryMXBean configRegistryMXBeanProxy; @@ -234,10 +233,15 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { throws ValidationException { try { configMBeanServer.invoke(configBeanON, "validate", null, null); + } catch (MBeanException e) { + Exception targetException = e.getTargetException(); + if (targetException instanceof ValidationException){ + throw (ValidationException) targetException; + } else { + throw new RuntimeException(e); + } } catch (JMException e) { throw new RuntimeException(e); - } catch (RuntimeMBeanException e) { - throw e.getTargetException(); } } diff --git a/opendaylight/config/logback-config/pom.xml b/opendaylight/config/logback-config/pom.xml index 4e0cfaada6..fbebda526a 100644 --- a/opendaylight/config/logback-config/pom.xml +++ b/opendaylight/config/logback-config/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT ../config-plugin-parent logback-config diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java index eeb8289e86..e543f752e1 100644 --- a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java +++ b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java @@ -7,24 +7,19 @@ */ package org.opendaylight.controller.config.yang.logback.config; -import static org.junit.Assert.assertEquals; - -import java.io.File; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.JMX; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.encoder.PatternLayoutEncoder; +import ch.qos.logback.classic.joran.JoranConfigurator; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.joran.spi.JoranException; +import ch.qos.logback.core.rolling.FixedWindowRollingPolicy; +import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy; +import com.google.common.collect.Lists; import org.apache.commons.io.FileUtils; import org.junit.Before; import org.junit.Test; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; @@ -32,15 +27,19 @@ import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; import org.slf4j.LoggerFactory; -import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.encoder.PatternLayoutEncoder; -import ch.qos.logback.classic.joran.JoranConfigurator; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.joran.spi.JoranException; -import ch.qos.logback.core.rolling.FixedWindowRollingPolicy; -import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.JMX; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import java.io.File; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; -import com.google.common.collect.Lists; +import static org.junit.Assert.assertEquals; public class LogbackModuleWithInitialConfigurationTest extends AbstractConfigTest { @@ -145,7 +144,7 @@ public class LogbackModuleWithInitialConfigurationTest extends AbstractConfigTes } public ObjectName createBeans() throws JoranException, InstanceAlreadyExistsException, IOException, - MalformedObjectNameException, InstanceNotFoundException { + MalformedObjectNameException, InstanceNotFoundException, ValidationException, ConflictingVersionException { LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java index 8718f8a9ce..8149659812 100644 --- a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java +++ b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java @@ -7,32 +7,31 @@ */ package org.opendaylight.controller.config.yang.logback.config; -import static org.junit.Assert.assertEquals; - -import java.io.File; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.util.List; - -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.JMX; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.joran.JoranConfigurator; +import ch.qos.logback.core.joran.spi.JoranException; +import com.google.common.collect.Lists; import org.apache.commons.io.FileUtils; import org.junit.Before; import org.junit.Test; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; import org.slf4j.LoggerFactory; -import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.joran.JoranConfigurator; -import ch.qos.logback.core.joran.spi.JoranException; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.JMX; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import java.io.File; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.List; -import com.google.common.collect.Lists; +import static org.junit.Assert.assertEquals; public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { @@ -61,7 +60,7 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { * @throws MalformedObjectNameException */ @Test - public void test() throws InstanceAlreadyExistsException, InstanceNotFoundException, MalformedObjectNameException { + public void test() throws InstanceAlreadyExistsException, InstanceNotFoundException, MalformedObjectNameException, ValidationException, ConflictingVersionException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), LogbackModuleFactory.INSTANCE_NAME); @@ -106,7 +105,7 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest { */ @Test public void testAddNewLogger() throws InstanceAlreadyExistsException, InstanceNotFoundException, - MalformedObjectNameException { + MalformedObjectNameException, ValidationException, ConflictingVersionException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), LogbackModuleFactory.INSTANCE_NAME); diff --git a/opendaylight/config/netty-config-api/pom.xml b/opendaylight/config/netty-config-api/pom.xml index fd099b3242..2a53e445f5 100644 --- a/opendaylight/config/netty-config-api/pom.xml +++ b/opendaylight/config/netty-config-api/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT ../config-plugin-parent 4.0.0 diff --git a/opendaylight/config/netty-event-executor-config/pom.xml b/opendaylight/config/netty-event-executor-config/pom.xml index 88afa13155..452c5ac715 100644 --- a/opendaylight/config/netty-event-executor-config/pom.xml +++ b/opendaylight/config/netty-event-executor-config/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT ../config-plugin-parent 4.0.0 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/netty-threadgroup-config/pom.xml b/opendaylight/config/netty-threadgroup-config/pom.xml index 172fe7f1fc..54143355f4 100644 --- a/opendaylight/config/netty-threadgroup-config/pom.xml +++ b/opendaylight/config/netty-threadgroup-config/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT ../config-plugin-parent diff --git a/opendaylight/config/netty-timer-config/pom.xml b/opendaylight/config/netty-timer-config/pom.xml index 9d3b5505ce..a056a1c126 100644 --- a/opendaylight/config/netty-timer-config/pom.xml +++ b/opendaylight/config/netty-timer-config/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT ../config-plugin-parent 4.0.0 diff --git a/opendaylight/config/pom.xml b/opendaylight/config/pom.xml index 3474740ca1..4ec7e2f64b 100644 --- a/opendaylight/config/pom.xml +++ b/opendaylight/config/pom.xml @@ -10,7 +10,7 @@ - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT config-subsystem pom ${project.artifactId} @@ -68,7 +68,6 @@ 0.6.2.201302030002 1.7.2 ${project.build.directory}/generated-sources/sal - 0.2.4-SNAPSHOT diff --git a/opendaylight/config/shutdown-api/pom.xml b/opendaylight/config/shutdown-api/pom.xml index 99a88fe209..1e14bc4961 100644 --- a/opendaylight/config/shutdown-api/pom.xml +++ b/opendaylight/config/shutdown-api/pom.xml @@ -3,7 +3,7 @@ config-plugin-parent org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT ../config-plugin-parent 4.0.0 diff --git a/opendaylight/config/shutdown-impl/pom.xml b/opendaylight/config/shutdown-impl/pom.xml index fa661b4ab8..8cf164d2a5 100644 --- a/opendaylight/config/shutdown-impl/pom.xml +++ b/opendaylight/config/shutdown-impl/pom.xml @@ -3,7 +3,7 @@ config-plugin-parent org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT ../config-plugin-parent 4.0.0 diff --git a/opendaylight/config/shutdown-impl/src/test/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownTest.java b/opendaylight/config/shutdown-impl/src/test/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownTest.java index d1abe08d52..d4a3160b89 100644 --- a/opendaylight/config/shutdown-impl/src/test/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownTest.java +++ b/opendaylight/config/shutdown-impl/src/test/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownTest.java @@ -11,6 +11,8 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; @@ -92,7 +94,7 @@ public class ShutdownTest extends AbstractConfigTest { shutdownViaRuntimeJMX(secret); } - private void setSecret(String secret) throws InstanceNotFoundException { + private void setSecret(String secret) throws InstanceNotFoundException, ValidationException, ConflictingVersionException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); ObjectName on = transaction.lookupConfigBean(NAME, NAME); ShutdownModuleMXBean proxy = transaction.newMXBeanProxy(on, ShutdownModuleMXBean.class); diff --git a/opendaylight/config/threadpool-config-api/pom.xml b/opendaylight/config/threadpool-config-api/pom.xml index 2f5e35c26d..7e45fa3c6b 100644 --- a/opendaylight/config/threadpool-config-api/pom.xml +++ b/opendaylight/config/threadpool-config-api/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT ../config-plugin-parent 4.0.0 diff --git a/opendaylight/config/threadpool-config-impl/pom.xml b/opendaylight/config/threadpool-config-impl/pom.xml index 08f1d554f6..fcedbd85f1 100644 --- a/opendaylight/config/threadpool-config-impl/pom.xml +++ b/opendaylight/config/threadpool-config-impl/pom.xml @@ -4,7 +4,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT ../config-plugin-parent 4.0.0 diff --git a/opendaylight/config/yang-jmx-generator-it/pom.xml b/opendaylight/config/yang-jmx-generator-it/pom.xml index a0ef5c2735..f081b7bd38 100644 --- a/opendaylight/config/yang-jmx-generator-it/pom.xml +++ b/opendaylight/config/yang-jmx-generator-it/pom.xml @@ -4,7 +4,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT yang-jmx-generator-it diff --git a/opendaylight/config/yang-jmx-generator-plugin/pom.xml b/opendaylight/config/yang-jmx-generator-plugin/pom.xml index f6d1c88c83..a8119b81ae 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/pom.xml +++ b/opendaylight/config/yang-jmx-generator-plugin/pom.xml @@ -3,7 +3,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT .. yang-jmx-generator-plugin 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/pom.xml b/opendaylight/config/yang-jmx-generator/pom.xml index b6e89cb92e..92ce0feccd 100644 --- a/opendaylight/config/yang-jmx-generator/pom.xml +++ b/opendaylight/config/yang-jmx-generator/pom.xml @@ -4,7 +4,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT yang-jmx-generator 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-store-api/pom.xml b/opendaylight/config/yang-store-api/pom.xml index b071025c1a..dfd9adb23f 100644 --- a/opendaylight/config/yang-store-api/pom.xml +++ b/opendaylight/config/yang-store-api/pom.xml @@ -3,7 +3,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT .. yang-store-api diff --git a/opendaylight/config/yang-store-impl/pom.xml b/opendaylight/config/yang-store-impl/pom.xml index c4ac830591..8a88cd04f9 100644 --- a/opendaylight/config/yang-store-impl/pom.xml +++ b/opendaylight/config/yang-store-impl/pom.xml @@ -3,7 +3,7 @@ config-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT .. yang-store-impl diff --git a/opendaylight/config/yang-test-plugin/pom.xml b/opendaylight/config/yang-test-plugin/pom.xml index fe7358ee90..0b4fc8b1b5 100644 --- a/opendaylight/config/yang-test-plugin/pom.xml +++ b/opendaylight/config/yang-test-plugin/pom.xml @@ -3,7 +3,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT ../config-plugin-parent 4.0.0 diff --git a/opendaylight/config/yang-test/pom.xml b/opendaylight/config/yang-test/pom.xml index 9037ff0c0f..6caee4108a 100644 --- a/opendaylight/config/yang-test/pom.xml +++ b/opendaylight/config/yang-test/pom.xml @@ -5,7 +5,7 @@ org.opendaylight.controller config-plugin-parent - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT ../config-plugin-parent 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/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java b/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java index b94103fb1c..bdbf7acd5f 100644 --- a/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java +++ b/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java @@ -1121,7 +1121,10 @@ public class ForwardingRulesManager implements List list = new ArrayList(groupFlows.get(groupName)); toBeRemoved = list.size(); for (FlowEntryInstall entry : list) { - Status status = this.removeEntry(entry.getOriginal(), false); + // since this is the entry that was stored in groupFlows + // it is already validated and merged + // so can call removeEntryInternal directly + Status status = this.removeEntryInternal(entry, false); if (status.isSuccess()) { toBeRemoved -= 1; } else { diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java index 84508ca03e..01d75acfe6 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java @@ -8,10 +8,8 @@ package org.opendaylight.controller.sal.compatibility.adsal; import java.math.BigInteger; -import java.util.concurrent.Future; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.controller.sal.common.util.Futures; import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.controller.sal.compatibility.InventoryMapping; import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils; @@ -37,6 +35,9 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListener { private static final Logger LOG = LoggerFactory.getLogger(FlowServiceAdapter.class); @@ -59,7 +60,7 @@ public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListen } @Override - public Future> addFlow(AddFlowInput input) { + public ListenableFuture> addFlow(AddFlowInput input) { Flow flow = ToSalConversionsUtils.toFlow(input, null); @SuppressWarnings("unchecked") @@ -73,7 +74,7 @@ public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListen } @Override - public Future> removeFlow(RemoveFlowInput input) { + public ListenableFuture> removeFlow(RemoveFlowInput input) { Flow flow = ToSalConversionsUtils.toFlow(input, null); @SuppressWarnings("unchecked") @@ -88,7 +89,7 @@ public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListen } @Override - public Future> updateFlow(UpdateFlowInput input) { + public ListenableFuture> updateFlow(UpdateFlowInput input) { @SuppressWarnings("unchecked") org.opendaylight.controller.sal.core.Node node = InventoryMapping.toAdNode((InstanceIdentifier) input .getNode().getValue()); diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java index 4bc23fe33b..c5cbecabed 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java @@ -13,7 +13,6 @@ import java.util.List; import java.util.concurrent.Future; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.controller.sal.common.util.Futures; import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.controller.sal.compatibility.FromSalConversionsUtils; import org.opendaylight.controller.sal.compatibility.InventoryMapping; @@ -64,6 +63,9 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, IReadServiceListener{ private static final Logger LOG = LoggerFactory.getLogger(FlowStatisticsAdapter.class); @@ -73,7 +75,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, @Override public Future> getAggregateFlowStatisticsFromFlowTableForAllFlows( GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput input) { - //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and + //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and // generating aggregate flow statistics out of those individual flow stats. return null; } @@ -81,13 +83,13 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, @Override public Future> getAggregateFlowStatisticsFromFlowTableForGivenMatch( GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput input) { - //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and + //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and // generating aggregate flow statistics out of those individual flow stats. return null; } @Override - public Future> getAllFlowStatisticsFromFlowTable( + public ListenableFuture> getAllFlowStatisticsFromFlowTable( GetAllFlowStatisticsFromFlowTableInput input) { GetAllFlowStatisticsFromFlowTableOutput rpcResultType = null; boolean rpcResultBool = false; @@ -99,7 +101,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, GetAllFlowStatisticsFromFlowTableOutputBuilder builder = new GetAllFlowStatisticsFromFlowTableOutputBuilder(); builder.setTransactionId(new TransactionId(new BigInteger("0"))); rpcResultType = builder.setFlowAndStatisticsMapList(flowsStatistics).build(); - + rpcResultBool = true; } catch (ConstructionException e) { LOG.error(e.getMessage()); @@ -112,9 +114,9 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, * Essentially this API will return the same result as getAllFlowStatisticsFromFlowTable */ @Override - public Future> getAllFlowsStatisticsFromAllFlowTables( + public ListenableFuture> getAllFlowsStatisticsFromAllFlowTables( GetAllFlowsStatisticsFromAllFlowTablesInput input) { - + GetAllFlowsStatisticsFromAllFlowTablesOutput rpcResultType = null; boolean rpcResultBool = false; @@ -125,7 +127,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, GetAllFlowsStatisticsFromAllFlowTablesOutputBuilder builder = new GetAllFlowsStatisticsFromAllFlowTablesOutputBuilder(); builder.setTransactionId(new TransactionId(new BigInteger("0"))); rpcResultType = builder.setFlowAndStatisticsMapList(flowsStatistics).build(); - + rpcResultBool = true; } catch (ConstructionException e) { LOG.error(e.getMessage()); @@ -135,7 +137,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, } @Override - public Future> getFlowStatisticsFromFlowTable( + public ListenableFuture> getFlowStatisticsFromFlowTable( GetFlowStatisticsFromFlowTableInput input) { GetFlowStatisticsFromFlowTableOutput rpcResultType = null; boolean rpcResultBool = false; @@ -170,7 +172,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, public void nodeConnectorStatisticsUpdated(Node node, List ncStatsList) { NodeConnectorStatisticsUpdateBuilder nodeConnectorStatisticsUpdateBuilder = new NodeConnectorStatisticsUpdateBuilder(); List nodeConnectorStatistics = toOdNodeConnectorStatistics(ncStatsList); - + nodeConnectorStatisticsUpdateBuilder.setNodeConnectorStatisticsAndPortNumberMap(nodeConnectorStatistics); nodeConnectorStatisticsUpdateBuilder.setMoreReplies(false); nodeConnectorStatisticsUpdateBuilder.setTransactionId(null); @@ -180,9 +182,9 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, @Override public void nodeTableStatisticsUpdated(Node node, List tableStatsList) { - - FlowTableStatisticsUpdateBuilder flowTableStatisticsUpdateBuilder = new FlowTableStatisticsUpdateBuilder(); - + + FlowTableStatisticsUpdateBuilder flowTableStatisticsUpdateBuilder = new FlowTableStatisticsUpdateBuilder(); + List flowTableStatistics = toOdFlowTableStatistics(tableStatsList); flowTableStatisticsUpdateBuilder.setFlowTableAndStatisticsMap(flowTableStatistics); flowTableStatisticsUpdateBuilder.setMoreReplies(false); @@ -194,7 +196,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, @Override public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) { // TODO which *StatisticsUpdated interface should be used? - + } private List toOdFlowsStatistics(List flowsOnNode) { @@ -234,7 +236,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, } private List toOdFlowTableStatistics(List tableStatsList) { - + List flowTableStatsMap = new ArrayList(); for (NodeTableStatistics nodeTableStatistics : tableStatsList) { FlowTableAndStatisticsMapBuilder flowTableAndStatisticsMapBuilder = new FlowTableAndStatisticsMapBuilder(); @@ -245,7 +247,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, flowTableAndStatisticsMapBuilder.setTableId(new TableId((short)nodeTableStatistics.getNodeTable().getID())); flowTableStatsMap.add(flowTableAndStatisticsMapBuilder.build()); } - + return flowTableStatsMap; } @@ -254,7 +256,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, List nodeConnectorStatisticsList = new ArrayList(); for(NodeConnectorStatistics ofNodeConnectorStatistics : ncStatsList){ NodeConnectorStatisticsAndPortNumberMapBuilder nodeConnectorStatisticsAndPortNumberMapBuilder = new NodeConnectorStatisticsAndPortNumberMapBuilder(); - + nodeConnectorStatisticsAndPortNumberMapBuilder.setBytes(extractBytes(ofNodeConnectorStatistics)); nodeConnectorStatisticsAndPortNumberMapBuilder.setCollisionCount(toBI(ofNodeConnectorStatistics.getCollisionCount())); nodeConnectorStatisticsAndPortNumberMapBuilder.setDuration(null); @@ -268,7 +270,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, nodeConnectorStatisticsAndPortNumberMapBuilder.setTransmitErrors(toBI(ofNodeConnectorStatistics.getTransmitErrorCount())); nodeConnectorStatisticsList.add(nodeConnectorStatisticsAndPortNumberMapBuilder.build()); } - + return nodeConnectorStatisticsList; } diff --git a/opendaylight/md-sal/model/pom.xml b/opendaylight/md-sal/model/pom.xml index 5092995eb0..1ea0a3e132 100644 --- a/opendaylight/md-sal/model/pom.xml +++ b/opendaylight/md-sal/model/pom.xml @@ -47,7 +47,6 @@ org.opendaylight.yangtools yang-maven-plugin - ${yangtools.version} diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index f900c0b18c..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 @@ -120,7 +120,7 @@ ${user.name}-private-view java 3.0.0 - 0.7.1-SNAPSHOT + 0.8.1-SNAPSHOT @@ -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/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java index 2da031e540..e5e314cd87 100644 --- a/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java +++ b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java @@ -7,25 +7,33 @@ */ package org.opendaylight.controller.sal.connector.remoterpc.api; -import java.util.Map; import java.util.Set; public interface RoutingTable { - - /** - * Adds a network address for the route. If address for route - * exists, appends the address to the list + * Adds a network address for the route. If the route already exists, + * it throws DuplicateRouteException. + * This method would be used when registering a global service. + * * * @param routeId route identifier * @param route network address - * @throws RoutingTableException for any logical exception + * @throws DuplicateRouteException + * @throws RoutingTableException + */ + public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException; + + /** + * Remove the route. + * This method would be used when registering a global service. + * @param routeId + * @throws RoutingTableException * @throws SystemException */ - public void addRoute(I routeId, R route) throws RoutingTableException,SystemException; + public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException; - /** + /** * Adds a network address for the route. If the route already exists, * it throws DuplicateRouteException. * This method would be used when registering a global service. @@ -36,9 +44,18 @@ public interface RoutingTable { * @throws DuplicateRouteException * @throws RoutingTableException */ - public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException; - + public R getGlobalRoute(I routeId) throws RoutingTableException, SystemException; + /** + * Adds a network address for the route. If address for route + * exists, appends the address to the list + * + * @param routeId route identifier + * @param route network address + * @throws RoutingTableException for any logical exception + * @throws SystemException + */ + public void addRoute(I routeId, R route) throws RoutingTableException,SystemException; /** @@ -47,17 +64,28 @@ public interface RoutingTable { * @param routeId * @param route */ - public void removeRoute(I routeId, R route); + public void removeRoute(I routeId, R route) throws RoutingTableException,SystemException; + /** + * Adds address for a set of route identifiers. If address for route + * exists, appends the address to the set. + * + * @param routeIds a set of routeIds + * @param route network address + * @throws RoutingTableException for any logical exception + * @throws SystemException + */ + public void addRoutes(Set routeIds, R route) throws RoutingTableException,SystemException; - /** - * Remove the route. - * This method would be used when registering a global service. - * @param routeId - * @throws RoutingTableException - * @throws SystemException - */ - public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException; + /** + * Removes address for a set of route identifiers. + * + * @param routeIds a set of routeIds + * @param route network address + * @throws RoutingTableException for any logical exception + * @throws SystemException + */ + public void removeRoutes(Set routeIds, R route) throws RoutingTableException,SystemException; /** * Returns a set of network addresses associated with this route @@ -66,29 +94,14 @@ public interface RoutingTable { */ public Set getRoutes(I routeId); - /** - * Returns all network addresses stored in the table - * @return - */ - public Set getAllRoutes(); /** - * Returns only one address from the list of network addresses - * associated with the route. The algorithm to determine that - * one address is upto the implementer + * Returns the last inserted address from the list of network addresses + * associated with the route. * @param routeId * @return */ - public R getARoute(I routeId); - - /** - * - * This will be removed after listeners - * have made change on their end to use whiteboard pattern - * @deprecated - */ - - public void registerRouteChangeListener(RouteChangeListener listener); + public R getLastAddedRoute(I routeId); public class DuplicateRouteException extends RoutingTableException { public DuplicateRouteException(String message) { diff --git a/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java index 6e2d280a89..a826a3c1d7 100644 --- a/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java +++ b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java @@ -67,7 +67,8 @@ public class Activator extends ComponentActivatorAbstractBase { if (imp.equals(RoutingTableImpl.class)) { Dictionary> props = new Hashtable>(); Set propSet = new HashSet(); - propSet.add(RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE); + propSet.add(RoutingTableImpl.GLOBALRPC_CACHE); + propSet.add(RoutingTableImpl.RPC_CACHE); props.put(CACHE_UPDATE_AWARE_REGISTRY_KEY, propSet); c.setInterface(new String[] { RoutingTable.class.getName(),ICacheUpdateAware.class.getName() }, props); diff --git a/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java index 40c4c6b436..d6b42faccf 100644 --- a/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java +++ b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java @@ -8,15 +8,11 @@ package org.opendaylight.controller.sal.connector.remoterpc.impl; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; import org.apache.felix.dm.Component; -import org.opendaylight.controller.clustering.services.CacheConfigException; -import org.opendaylight.controller.clustering.services.CacheExistException; -import org.opendaylight.controller.clustering.services.CacheListenerAddException; -import org.opendaylight.controller.clustering.services.ICacheUpdateAware; -import org.opendaylight.controller.clustering.services.IClusterGlobalServices; -import org.opendaylight.controller.clustering.services.IClusterServices; -import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener; +import org.opendaylight.controller.clustering.services.*; import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable; import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException; import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException; @@ -27,309 +23,415 @@ import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; import javax.transaction.NotSupportedException; import javax.transaction.RollbackException; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentMap; -/** - * @author: syedbahm - */ public class RoutingTableImpl implements RoutingTable, ICacheUpdateAware { - public static final String ROUTING_TABLE_GLOBAL_CACHE = "routing_table_global_cache"; - private Logger log = LoggerFactory.getLogger(RoutingTableImpl.class); + private Logger log = LoggerFactory.getLogger(RoutingTableImpl.class); - private IClusterGlobalServices clusterGlobalServices = null; - private RoutingTableImpl routingTableInstance = null; - private ConcurrentMap routingTableCache = null; - private Set routeChangeListeners = Collections - .synchronizedSet(new HashSet()); + private IClusterGlobalServices clusterGlobalServices = null; - public RoutingTableImpl() { - } + private ConcurrentMap globalRpcCache = null; + private ConcurrentMap> rpcCache = null; //need routes to ordered by insert-order - @Override - public void addRoute(I routeId, R route) throws RoutingTableException { - throw new UnsupportedOperationException(" Not implemented yet!"); - } + public static final String GLOBALRPC_CACHE = "remoterpc_routingtable.globalrpc_cache"; + public static final String RPC_CACHE = "remoterpc_routingtable.rpc_cache"; - @Override - public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException { - Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!"); - Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!"); - try { - - Set existingRoute = null; - // ok does the global route is already registered ? - if ((existingRoute = getRoutes(routeId)) == null) { - - if (log.isDebugEnabled()) { - log.debug("addGlobalRoute: adding a new route with id" + routeId + " and value = " - + route); - } - // lets start a transaction - clusterGlobalServices.tbegin(); - - routingTableCache.put(routeId, route); - clusterGlobalServices.tcommit(); - } else { - throw new DuplicateRouteException(" There is already existing route " + existingRoute); - } - - } catch (NotSupportedException|HeuristicRollbackException|RollbackException|HeuristicMixedException e) { - throw new RoutingTableException("Transaction error - while trying to create route id=" - + routeId + "with route" + route, e); - } catch (javax.transaction.SystemException e) { - throw new SystemException("System error occurred - while trying to create with value", e); - } + public RoutingTableImpl() { + } - } + @Override + public R getGlobalRoute(I routeId) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeId, "getGlobalRoute: routeId cannot be null!"); + return globalRpcCache.get(routeId); + } - @Override - public void removeRoute(I routeId, R route) { - throw new UnsupportedOperationException("Not implemented yet!"); + @Override + public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!"); + Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!"); + try { + + log.debug("addGlobalRoute: adding a new route with id[{}] and value [{}]", routeId, route); + clusterGlobalServices.tbegin(); + if (globalRpcCache.putIfAbsent(routeId, route) != null) { + throw new DuplicateRouteException(" There is already existing route " + routeId); + } + clusterGlobalServices.tcommit(); + + } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) { + throw new RoutingTableException("Transaction error - while trying to create route id=" + + routeId + "with route" + route, e); + } catch (javax.transaction.SystemException e) { + throw new SystemException("System error occurred - while trying to create with value", e); } - @Override - public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException { - Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!"); - try { - if (log.isDebugEnabled()) { - log.debug("removeGlobalRoute: removing a new route with id" + routeId); - } - // lets start a transaction - clusterGlobalServices.tbegin(); - - routingTableCache.remove(routeId); - clusterGlobalServices.tcommit(); - - } catch (NotSupportedException|HeuristicRollbackException|RollbackException|HeuristicMixedException e) { - throw new RoutingTableException("Transaction error - while trying to remove route id=" - + routeId, e); - } catch (javax.transaction.SystemException e) { - throw new SystemException("System error occurred - while trying to remove with value", e); - } + } + + @Override + public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!"); + try { + log.debug("removeGlobalRoute: removing a new route with id [{}]", routeId); + + clusterGlobalServices.tbegin(); + globalRpcCache.remove(routeId); + clusterGlobalServices.tcommit(); + + } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) { + throw new RoutingTableException("Transaction error - while trying to remove route id=" + + routeId, e); + } catch (javax.transaction.SystemException e) { + throw new SystemException("System error occurred - while trying to remove with value", e); } + } + - @Override - public Set getRoutes(I routeId) { + @Override + public Set getRoutes(I routeId) { + Preconditions.checkNotNull(routeId, "getRoutes: routeId cannot be null!"); + Set routes = rpcCache.get(routeId); - // Note: currently works for global routes only wherein there is just single - // route - Preconditions.checkNotNull(routeId, "getARoute: routeId cannot be null!"); - R route = (R)routingTableCache.get(routeId); - Setroutes = null; - if(route !=null){ - routes = new HashSet(); - routes.add(route); - } + if (routes == null) return Collections.emptySet(); + + return ImmutableSet.copyOf(routes); + } - return routes; - } + + + public R getLastAddedRoute(I routeId) { + + Set routes = getRoutes(routeId); + + if (routes.isEmpty()) return null; + + R route = null; + Iterator iter = routes.iterator(); + while (iter.hasNext()) + route = iter.next(); + + return route; + } @Override - public Set getAllRoutes() { - return routingTableCache.entrySet(); + public void addRoute(I routeId, R route) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeId, "addRoute: routeId cannot be null"); + Preconditions.checkNotNull(route, "addRoute: route cannot be null"); + + try{ + clusterGlobalServices.tbegin(); + log.debug("addRoute: adding a route with k/v [{}/{}]", routeId, route); + threadSafeAdd(routeId, route); + clusterGlobalServices.tcommit(); + + } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) { + throw new RoutingTableException("Transaction error - while trying to remove route id=" + + routeId, e); + } catch (javax.transaction.SystemException e) { + throw new SystemException("System error occurred - while trying to remove with value", e); + } } @Override - public R getARoute(I routeId) { - throw new UnsupportedOperationException("Not implemented yet!"); + public void addRoutes(Set routeIds, R route) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeIds, "addRoutes: routeIds must not be null"); + for (I routeId : routeIds){ + addRoute(routeId, route); } + } - /** - * @deprecated doesn't do anything will be removed once listeners used - * whiteboard pattern Registers listener for sending any change - * notification - * @param listener - */ - @Override - public void registerRouteChangeListener(RouteChangeListener listener) { + @Override + public void removeRoute(I routeId, R route) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeId, "removeRoute: routeId cannot be null!"); + Preconditions.checkNotNull(route, "removeRoute: route cannot be null!"); - } + LinkedHashSet routes = rpcCache.get(routeId); + if (routes == null) return; - public void setRouteChangeListener(RouteChangeListener rcl) { - if(rcl != null){ - routeChangeListeners.add(rcl); - }else{ - log.warn("setRouteChangeListener called with null listener"); - } - } + try { + log.debug("removeRoute: removing a new route with k/v [{}/{}]", routeId, route); - public void unSetRouteChangeListener(RouteChangeListener rcl) { - if(rcl != null){ - routeChangeListeners.remove(rcl); - }else{ - log.warn("unSetRouteChangeListener called with null listener"); - } + clusterGlobalServices.tbegin(); + threadSafeRemove(routeId, route); + clusterGlobalServices.tcommit(); + + } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) { + throw new RoutingTableException("Transaction error - while trying to remove route id=" + + routeId, e); + } catch (javax.transaction.SystemException e) { + throw new SystemException("System error occurred - while trying to remove with value", e); } + } - /** - * Returning the set of route change listeners for Unit testing Note: the - * package scope is default - * - * @return List of registered RouteChangeListener listeners - */ - Set getRegisteredRouteChangeListeners() { - return routeChangeListeners; + @Override + public void removeRoutes(Set routeIds, R route) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeIds, "removeRoutes: routeIds must not be null"); + for (I routeId : routeIds){ + removeRoute(routeId, route); } + } - public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) { - this.clusterGlobalServices = clusterGlobalServices; + /** + * This method guarantees that no 2 thread over write each other's changes. + * Just so that we dont end up in infinite loop, it tries for 100 times then throw + */ + private void threadSafeAdd(I routeId, R route) { + + for (int i=0;i<100;i++){ + + LinkedHashSet updatedRoutes = new LinkedHashSet<>(); + updatedRoutes.add(route); + LinkedHashSet oldRoutes = rpcCache.putIfAbsent(routeId, updatedRoutes); + if (oldRoutes == null) return; + + updatedRoutes = new LinkedHashSet<>(oldRoutes); + updatedRoutes.add(route); + + if (rpcCache.replace(routeId, oldRoutes, updatedRoutes)) return; } + //the method did not already return means it failed to add route in 10 attempts + throw new IllegalStateException("Failed to add route [" + routeId + "]"); + } + + /** + * This method guarantees that no 2 thread over write each other's changes. + * Just so that we dont end up in infinite loop, it tries for 10 times then throw + */ + private void threadSafeRemove(I routeId, R route) { + LinkedHashSet updatedRoutes = null; + for (int i=0;i<10;i++){ + LinkedHashSet oldRoutes = rpcCache.get(routeId); + + // if route to be deleted is the only entry in the set then remove routeId from the cache + if ((oldRoutes.size() == 1) && oldRoutes.contains(route)){ + rpcCache.remove(routeId); + return; + } + + // if there are multiple routes for this routeId, remove the route to be deleted only from the set. + updatedRoutes = new LinkedHashSet<>(oldRoutes); + updatedRoutes.remove(route); + if (rpcCache.replace(routeId, oldRoutes, updatedRoutes)) return; - public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) { - if((clusterGlobalServices != null ) && (this.clusterGlobalServices.equals(clusterGlobalServices))){ - this.clusterGlobalServices = null; - } } + //the method did not already return means it failed to remove route in 10 attempts + throw new IllegalStateException("Failed to remove route [" + routeId + "]"); + } + - /** - * Creates the Routing Table clustered global services cache - * - * @throws CacheExistException - * -- cluster global services exception when cache exist - * @throws CacheConfigException - * -- cluster global services exception during cache config - * @throws CacheListenerAddException - * -- cluster global services exception during adding of listener - */ - - void createRoutingTableCache() throws CacheExistException, CacheConfigException, - CacheListenerAddException { - // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it - // should be caching? - - // let us check here if the cache already exists -- if so don't create - if (!clusterGlobalServices.existCache(ROUTING_TABLE_GLOBAL_CACHE)) { - - if (log.isDebugEnabled()) { - log.debug("createRoutingTableCache: creating a new routing table cache " - + ROUTING_TABLE_GLOBAL_CACHE); - } - routingTableCache = clusterGlobalServices.createCache(ROUTING_TABLE_GLOBAL_CACHE, - EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); - } else { - if (log.isDebugEnabled()) { - log.debug("createRoutingTableCache: found existing routing table cache " - + ROUTING_TABLE_GLOBAL_CACHE); - } - routingTableCache = clusterGlobalServices.getCache(ROUTING_TABLE_GLOBAL_CACHE); - } +// /** +// * @deprecated doesn't do anything will be removed once listeners used +// * whiteboard pattern Registers listener for sending any change +// * notification +// * @param listener +// */ +// @Override +// public void registerRouteChangeListener(RouteChangeListener listener) { +// +// } + +// public void setRouteChangeListener(RouteChangeListener rcl) { +// if(rcl != null){ +// routeChangeListeners.add(rcl); +// }else{ +// log.warn("setRouteChangeListener called with null listener"); +// } +// } +// +// public void unSetRouteChangeListener(RouteChangeListener rcl) { +// if(rcl != null){ +// routeChangeListeners.remove(rcl); +// }else{ +// log.warn("unSetRouteChangeListener called with null listener"); +// } +// } + + /** + * Returning the set of route change listeners for Unit testing Note: the + * package scope is default + * + * @return List of registered RouteChangeListener listeners + */ +// Set getRegisteredRouteChangeListeners() { +// return routeChangeListeners; +// } + public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) { + this.clusterGlobalServices = clusterGlobalServices; + } + + public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) { + if ((clusterGlobalServices != null) && (this.clusterGlobalServices.equals(clusterGlobalServices))) { + this.clusterGlobalServices = null; + } + } + /** + * Finds OR Creates clustered cache for Global RPCs + * + * @throws CacheExistException -- cluster global services exception when cache exist + * @throws CacheConfigException -- cluster global services exception during cache config + * @throws CacheListenerAddException -- cluster global services exception during adding of listener + */ + + void findOrCreateGlobalRpcCache() throws CacheExistException, CacheConfigException, + CacheListenerAddException { + // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it + // should be caching? + + // let us check here if the cache already exists -- if so don't create + if (!clusterGlobalServices.existCache(GLOBALRPC_CACHE)) { + + globalRpcCache = (ConcurrentMap) clusterGlobalServices.createCache(GLOBALRPC_CACHE, + EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); + log.debug("Cache created [{}] ", GLOBALRPC_CACHE); + + } else { + globalRpcCache = (ConcurrentMap) clusterGlobalServices.getCache(GLOBALRPC_CACHE); + log.debug("Cache exists [{}] ", GLOBALRPC_CACHE); } + } - /** - * Function called by the dependency manager when all the required - * dependencies are satisfied - * - */ - void init(Component c) { - try { - - createRoutingTableCache(); - } catch (CacheExistException e) { - throw new IllegalStateException("could not construct routing table cache"); - } catch (CacheConfigException e) { - throw new IllegalStateException("could not construct routing table cache"); - } catch (CacheListenerAddException e) { - throw new IllegalStateException("could not construct routing table cache"); - } + /** + * Finds OR Creates clustered cache for Routed RPCs + * + * @throws CacheExistException -- cluster global services exception when cache exist + * @throws CacheConfigException -- cluster global services exception during cache config + * @throws CacheListenerAddException -- cluster global services exception during adding of listener + */ + + void findOrCreateRpcCache() throws CacheExistException, CacheConfigException, + CacheListenerAddException { + // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it + // should be caching? + + if (clusterGlobalServices.existCache(RPC_CACHE)){ + rpcCache = (ConcurrentMap>) clusterGlobalServices.getCache(RPC_CACHE); + log.debug("Cache exists [{}] ", RPC_CACHE); + return; } - /** - * Get routing table method is useful for unit testing It has package - * scope - */ - ConcurrentMap getRoutingTableCache() { - return this.routingTableCache; + //cache doesnt exist, create one + rpcCache = (ConcurrentMap>) clusterGlobalServices.createCache(RPC_CACHE, + EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); + log.debug("Cache created [{}] ", RPC_CACHE); + } + + + /** + * Function called by the dependency manager when all the required + * dependencies are satisfied + */ + void init(Component c) { + try { + + findOrCreateGlobalRpcCache(); + findOrCreateRpcCache(); + + } catch (CacheExistException|CacheConfigException|CacheListenerAddException e) { + throw new IllegalStateException("could not construct routing table cache"); } + } + + /** + * Useful for unit testing It has package + * scope + */ + ConcurrentMap getGlobalRpcCache() { + return this.globalRpcCache; + } + + /** + * Useful for unit testing It has package + * scope + */ + ConcurrentMap getRpcCache() { + return this.rpcCache; + } - /** - * This is used from integration test NP rest API to check out the result of the - * cache population - * For testing purpose only-- use it wisely - * @return - */ - public String dumpRoutingTableCache(){ - Set> cacheEntrySet = this.routingTableCache.entrySet(); - StringBuilder sb = new StringBuilder(); - for(Map.Entry entry:cacheEntrySet){ - sb.append("Key:").append(entry.getKey()).append("---->Value:") - .append((entry.getValue() != null)?entry.getValue():"null") - .append("\n"); - } - return sb.toString(); + /** + * This is used from integration test NP rest API to check out the result of the + * cache population + * For testing purpose only-- use it wisely + * + * @return + */ + public String dumpGlobalRpcCache() { + Set> cacheEntrySet = this.globalRpcCache.entrySet(); + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : cacheEntrySet) { + sb.append("Key:").append(entry.getKey()).append("---->Value:") + .append((entry.getValue() != null) ? entry.getValue() : "null") + .append("\n"); } + return sb.toString(); + } - /** - * Invoked when a new entry is available in the cache, the key is only - * provided, the value will come as an entryUpdate invocation - * - * @param key - * Key for the entry just created - * @param cacheName - * name of the cache for which update has been received - * @param originLocal - * true if the event is generated from this node - */ - @Override - public void entryCreated(I key, String cacheName, boolean originLocal) { - // TBD: do we require this. - if (log.isDebugEnabled()) { - log.debug("RoutingTableUpdates: entryCreated routeId = " + key + " cacheName=" + cacheName); - } + public String dumpRpcCache() { + Set>> cacheEntrySet = this.rpcCache.entrySet(); + StringBuilder sb = new StringBuilder(); + for (Map.Entry> entry : cacheEntrySet) { + sb.append("Key:").append(entry.getKey()).append("---->Value:") + .append((entry.getValue() != null) ? entry.getValue() : "null") + .append("\n"); } + return sb.toString(); + } + /** + * Invoked when a new entry is available in the cache, the key is only + * provided, the value will come as an entryUpdate invocation + * + * @param key Key for the entry just created + * @param cacheName name of the cache for which update has been received + * @param originLocal true if the event is generated from this node + */ + @Override + public void entryCreated(I key, String cacheName, boolean originLocal) { + // TBD: do we require this. + if (log.isDebugEnabled()) { + log.debug("RoutingTableUpdates: entryCreated routeId = " + key + " cacheName=" + cacheName); + } + } - /** - * Called anytime a given entry is updated - * - * @param key - * Key for the entry modified - * @param new_value - * the new value the key will have - * @param cacheName - * name of the cache for which update has been received - * @param originLocal - * true if the event is generated from this node - */ - @Override - public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) { - if (log.isDebugEnabled()) { - log.debug("RoutingTableUpdates: entryUpdated routeId = " + key + ",value = " + new_value - + " ,cacheName=" + cacheName + " originLocal="+originLocal); - } - if (!originLocal) { - for (RouteChangeListener rcl : routeChangeListeners) { - rcl.onRouteUpdated(key, new_value); - } - } + /** + * Called anytime a given entry is updated + * + * @param key Key for the entry modified + * @param new_value the new value the key will have + * @param cacheName name of the cache for which update has been received + * @param originLocal true if the event is generated from this node + */ + @Override + public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) { + if (log.isDebugEnabled()) { + log.debug("RoutingTableUpdates: entryUpdated routeId = " + key + ",value = " + new_value + + " ,cacheName=" + cacheName + " originLocal=" + originLocal); } +// if (!originLocal) { +// for (RouteChangeListener rcl : routeChangeListeners) { +// rcl.onRouteUpdated(key, new_value); +// } +// } + } - /** - * Called anytime a given key is removed from the ConcurrentHashMap we are - * listening to. - * - * @param key - * Key of the entry removed - * @param cacheName - * name of the cache for which update has been received - * @param originLocal - * true if the event is generated from this node - */ - @Override - public void entryDeleted(I key, String cacheName, boolean originLocal) { - if (log.isDebugEnabled()) { - log.debug("RoutingTableUpdates: entryUpdated routeId = " + key + " local = " + originLocal - + " cacheName=" + cacheName + " originLocal="+originLocal); - } - if (!originLocal) { - for (RouteChangeListener rcl : routeChangeListeners) { - rcl.onRouteDeleted(key); - } - } + /** + * Called anytime a given key is removed from the ConcurrentHashMap we are + * listening to. + * + * @param key Key of the entry removed + * @param cacheName name of the cache for which update has been received + * @param originLocal true if the event is generated from this node + */ + @Override + public void entryDeleted(I key, String cacheName, boolean originLocal) { + if (log.isDebugEnabled()) { + log.debug("RoutingTableUpdates: entryUpdated routeId = " + key + " local = " + originLocal + + " cacheName=" + cacheName + " originLocal=" + originLocal); } +// if (!originLocal) { +// for (RouteChangeListener rcl : routeChangeListeners) { +// rcl.onRouteDeleted(key); +// } +// } + } } \ No newline at end of file diff --git a/opendaylight/md-sal/remoterpc-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java index 50460d4e5e..0987df5956 100644 --- a/opendaylight/md-sal/remoterpc-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java +++ b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java @@ -10,196 +10,321 @@ package org.opendaylight.controller.sal.connector.remoterpc.impl; import junit.framework.Assert; import org.apache.felix.dm.Component; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.opendaylight.controller.clustering.services.IClusterGlobalServices; import org.opendaylight.controller.clustering.services.IClusterServices; import org.opendaylight.controller.sal.connector.api.RpcRouter; -import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener; +import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable; +import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException; +import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import java.net.URI; import java.util.EnumSet; import java.util.HashSet; -import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.Set; -import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; -/** - * @author: syedbahm - */ public class RoutingTableImplTest { - private IClusterGlobalServices ics = mock(IClusterGlobalServices.class); - private RoutingTableImpl rti = new RoutingTableImpl(); + private final URI namespace = URI.create("http://cisco.com/example"); + private final QName QNAME = new QName(namespace, "global"); - private final URI namespace = URI.create("http://cisco.com/example"); - private final QName QNAME = new QName(namespace,"global"); + private IClusterGlobalServices clusterService; + private RoutingTableImpl, String> routingTable; + ConcurrentMap mockGlobalRpcCache; + ConcurrentMap mockRpcCache; - ConcurrentMap concurrentMapMock = mock(ConcurrentMap.class); + @Before + public void setUp() throws Exception{ + clusterService = mock(IClusterGlobalServices.class); + routingTable = new RoutingTableImpl, String>(); + mockGlobalRpcCache = new ConcurrentHashMap<>(); + mockRpcCache = new ConcurrentHashMap<>(); + createRoutingTableCache(); + } + @After + public void tearDown(){ + reset(clusterService); + mockGlobalRpcCache = null; + mockRpcCache = null; + } - @Test - public void testAddGlobalRoute() throws Exception { - ConcurrentMap concurrentMap = createRoutingTableCache(); + @Test + public void addGlobalRoute_ValidArguments_ShouldAdd() throws Exception { - Assert.assertNotNull(concurrentMap); - RpcRouter.RouteIdentifier routeIdentifier = mock(RpcRouter.RouteIdentifier.class); - InstanceIdentifier identifier = mock(InstanceIdentifier.class); - when(routeIdentifier.getType()).thenReturn(QNAME); - when(routeIdentifier.getRoute()).thenReturn(identifier); + Assert.assertNotNull(mockGlobalRpcCache); + RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); - rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000"); + final String expectedRoute = "172.27.12.1:5000"; + routingTable.addGlobalRoute(routeIdentifier, expectedRoute); - Set globalService = new HashSet(); - globalService.add("172.27.12.1:5000"); + ConcurrentMap latestCache = routingTable.getGlobalRpcCache(); + Assert.assertEquals(mockGlobalRpcCache, latestCache); + Assert.assertEquals(expectedRoute, latestCache.get(routeIdentifier)); + } - when(concurrentMap.get(routeIdentifier)).thenReturn(globalService); - ConcurrentMap latestCache = rti.getRoutingTableCache(); + @Test (expected = RoutingTable.DuplicateRouteException.class) + public void addGlobalRoute_DuplicateRoute_ShouldThrow() throws Exception{ - Assert.assertEquals(concurrentMap,latestCache); + Assert.assertNotNull(mockGlobalRpcCache); - Set servicesGlobal = (Set)latestCache.get(routeIdentifier); - Assert.assertEquals(servicesGlobal.size(),1); + RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); + routingTable.addGlobalRoute(routeIdentifier, new String()); + routingTable.addGlobalRoute(routeIdentifier, new String()); + } - Assert.assertEquals(servicesGlobal.iterator().next(),"172.27.12.1:5000"); + @Test + public void getGlobalRoute_ExistingRouteId_ShouldReturnRoute() throws Exception { - } + Assert.assertNotNull(mockGlobalRpcCache); + RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); + String expectedRoute = "172.27.12.1:5000"; - @Test - public void testGetRoutes() throws Exception { - ConcurrentMap concurrentMap = createRoutingTableCache(); + routingTable.addGlobalRoute(routeIdentifier, expectedRoute); - Assert.assertNotNull(concurrentMap); - RpcRouter.RouteIdentifier routeIdentifier = mock(RpcRouter.RouteIdentifier.class); - InstanceIdentifier identifier = mock(InstanceIdentifier.class); - when(routeIdentifier.getContext()).thenReturn(QNAME); - when(routeIdentifier.getRoute()).thenReturn(identifier); + String actualRoute = (String) routingTable.getGlobalRoute(routeIdentifier); + Assert.assertEquals(expectedRoute, actualRoute); + } - rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000"); + @Test + public void getGlobalRoute_NonExistentRouteId_ShouldReturnNull() throws Exception { - String globalService = "172.27.12.1:5000"; + Assert.assertNotNull(mockGlobalRpcCache); + RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); - when(concurrentMap.get(routeIdentifier)).thenReturn(globalService); - ConcurrentMap latestCache = rti.getRoutingTableCache(); + String actualRoute = (String) routingTable.getGlobalRoute(routeIdentifier); + Assert.assertNull(actualRoute); + } - Assert.assertEquals(concurrentMap,latestCache); + @Test + public void removeGlobalRoute_ExistingRouteId_ShouldRemove() throws Exception { - Set servicesGlobal = rti.getRoutes(routeIdentifier); + Assert.assertNotNull(mockGlobalRpcCache); + RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); + ConcurrentMap cache = routingTable.getGlobalRpcCache(); + Assert.assertTrue(cache.size() == 0); + routingTable.addGlobalRoute(routeIdentifier, "172.27.12.1:5000"); + Assert.assertTrue(cache.size() == 1); - Assert.assertEquals(servicesGlobal.size(),1); - Iterator iterator = servicesGlobal.iterator(); - while(iterator.hasNext()){ - Assert.assertEquals(iterator.next(),"172.27.12.1:5000"); - } + routingTable.removeGlobalRoute(routeIdentifier); + Assert.assertTrue(cache.size() == 0); + } - } - @Test - public void testRegisterRouteChangeListener() throws Exception { - Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),0); - rti.registerRouteChangeListener(new RouteChangeListenerImpl()); + @Test + public void removeGlobalRoute_NonExistentRouteId_ShouldDoNothing() throws Exception { - Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),0); //old should not work - //what about the new approach - using whiteboard pattern - rti.setRouteChangeListener(new RouteChangeListenerImpl()); + Assert.assertNotNull(mockGlobalRpcCache); + RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); - Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),1); //should not work + ConcurrentMap cache = routingTable.getGlobalRpcCache(); + Assert.assertTrue(cache.size() == 0); + routingTable.removeGlobalRoute(routeIdentifier); + Assert.assertTrue(cache.size() == 0); - } - @Test - public void testRemoveGlobalRoute()throws Exception { + } - ConcurrentMap concurrentMap = createRoutingTableCache(); + @Test + public void addRoute_ForNewRouteId_ShouldAddRoute() throws Exception { + Assert.assertTrue(mockRpcCache.size() == 0); - Assert.assertNotNull(concurrentMap); - RpcRouter.RouteIdentifier routeIdentifier = mock(RpcRouter.RouteIdentifier.class); - InstanceIdentifier identifier = mock(InstanceIdentifier.class); - when(routeIdentifier.getContext()).thenReturn(QNAME); - when(routeIdentifier.getRoute()).thenReturn(identifier); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); - rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000"); + routingTable.addRoute(routeId, new String()); + Assert.assertTrue(mockRpcCache.size() == 1); - String globalService = "172.27.12.1:5000"; + Set routes = routingTable.getRoutes(routeId); + Assert.assertEquals(1, routes.size()); + } - when(concurrentMap.get(routeIdentifier)).thenReturn(globalService); - ConcurrentMap latestCache = rti.getRoutingTableCache(); + @Test + public void addRoute_ForExistingRouteId_ShouldAppendRoute() throws Exception { - Assert.assertEquals(concurrentMap,latestCache); + Assert.assertTrue(mockRpcCache.size() == 0); - Set servicesGlobal = rti.getRoutes(routeIdentifier); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + String route_1 = "10.0.0.1:5955"; + String route_2 = "10.0.0.2:5955"; - Assert.assertEquals(servicesGlobal.size(),1); + routingTable.addRoute(routeId, route_1); + routingTable.addRoute(routeId, route_2); - Assert.assertEquals(servicesGlobal.iterator().next(),"172.27.12.1:5000"); + Assert.assertTrue(mockRpcCache.size() == 1); - rti.removeGlobalRoute(routeIdentifier); + Set routes = routingTable.getRoutes(routeId); + Assert.assertEquals(2, routes.size()); + Assert.assertTrue(routes.contains(route_1)); + Assert.assertTrue(routes.contains(route_2)); + } - Assert.assertNotNull(rti.getRoutes(routeIdentifier)); + @Test + public void addRoute_UsingMultipleThreads_ShouldNotOverwrite(){ + ExecutorService threadPool = Executors.newCachedThreadPool(); + int numOfRoutesToAdd = 100; + String routePrefix_1 = "10.0.0.1:555"; + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + threadPool.submit(addRoutes(numOfRoutesToAdd, routePrefix_1, routeId)); + String routePrefix_2 = "10.0.0.1:556"; + threadPool.submit(addRoutes(numOfRoutesToAdd, routePrefix_2, routeId)); + // wait for all tasks to complete; timeout in 10 sec + threadPool.shutdown(); + try { + threadPool.awaitTermination(10, TimeUnit.SECONDS); // + } catch (InterruptedException e) { + e.printStackTrace(); } - private ConcurrentMap createRoutingTableCache() throws Exception { + Assert.assertEquals(2*numOfRoutesToAdd, routingTable.getRoutes(routeId).size()); + } - //here init - Component c = mock(Component.class); + @Test(expected = NullPointerException.class) + public void addRoute_NullRouteId_shouldThrowNpe() throws Exception { - when(ics.existCache( - RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(false); + routingTable.addRoute(null, new String()); + } - when(ics.createCache(RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(concurrentMapMock); - rti.setClusterGlobalServices(this.ics); - rti.init(c); + @Test(expected = NullPointerException.class) + public void addRoute_NullRoute_shouldThrowNpe() throws Exception{ - Assert.assertEquals(concurrentMapMock,rti.getRoutingTableCache() ); - return concurrentMapMock; + routingTable.addRoute(getRouteIdentifier(), null); + } - } + @Test (expected = UnsupportedOperationException.class) + public void getRoutes_Call_ShouldReturnImmutableCopy() throws Exception{ + Assert.assertNotNull(routingTable); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + routingTable.addRoute(routeId, new String()); + Set routes = routingTable.getRoutes(routeId); //returns Immutable Set - @Test - public void testCreateRoutingTableCacheReturnExistingCache() throws Exception { - ConcurrentMap concurrentMap = createRoutingTableCache(); + routes.add(new String()); //can not be modified; should throw + } - //OK here we should try creating again the cache but this time it should return the existing one - when(ics.existCache( - RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(true); + @Test + public void getRoutes_With2RoutesFor1RouteId_ShouldReturnASetWithSize2() throws Exception{ + Assert.assertNotNull(routingTable); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + routingTable.addRoute(routeId, "10.0.0.1:5555"); + routingTable.addRoute(routeId, "10.0.0.2:5555"); - when(ics.getCache( - RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(concurrentMap); + Set routes = routingTable.getRoutes(routeId); //returns Immutable Set + Assert.assertEquals(2, routes.size()); + } - //here init - Component c = mock(Component.class); + @Test + public void getLastAddedRoute_WhenMultipleRoutesExists_ShouldReturnLatestRoute() + throws Exception { - rti.init(c); + Assert.assertNotNull(routingTable); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + String route_1 = "10.0.0.1:5555"; + String route_2 = "10.0.0.2:5555"; + routingTable.addRoute(routeId, route_1); + routingTable.addRoute(routeId, route_2); - Assert.assertEquals(concurrentMap,rti.getRoutingTableCache()); + Assert.assertEquals(route_2, routingTable.getLastAddedRoute(routeId)); + } + @Test + public void removeRoute_WhenMultipleRoutesExist_RemovesGivenRoute() throws Exception{ + Assert.assertNotNull(routingTable); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + String route_1 = "10.0.0.1:5555"; + String route_2 = "10.0.0.2:5555"; + routingTable.addRoute(routeId, route_1); + routingTable.addRoute(routeId, route_2); + Assert.assertEquals(2, routingTable.getRoutes(routeId).size()); + routingTable.removeRoute(routeId, route_1); + Assert.assertEquals(1, routingTable.getRoutes(routeId).size()); - } + } - private class RouteChangeListenerImpl implements RouteChangeListener{ + @Test + public void removeRoute_WhenOnlyOneRouteExists_RemovesRouteId() throws Exception{ + Assert.assertNotNull(routingTable); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + String route_1 = "10.0.0.1:5555"; - @Override - public void onRouteUpdated(I key, R new_value) { - //To change body of implemented methods use File | Settings | File Templates. - } + routingTable.addRoute(routeId, route_1); + Assert.assertEquals(1, routingTable.getRoutes(routeId).size()); - @Override - public void onRouteDeleted(I key) { - //To change body of implemented methods use File | Settings | File Templates. - } - } + routingTable.removeRoute(routeId, route_1); + ConcurrentMap cache = routingTable.getRpcCache(); + Assert.assertFalse(cache.containsKey(routeId)); + + } + /* + * Private helper methods + */ + private void createRoutingTableCache() throws Exception { + + //here init + Component c = mock(Component.class); + + when(clusterService.existCache( + RoutingTableImpl.GLOBALRPC_CACHE)).thenReturn(false); + + when(clusterService.createCache(RoutingTableImpl.GLOBALRPC_CACHE, + EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))). + thenReturn(mockGlobalRpcCache); + + when(clusterService.existCache( + RoutingTableImpl.RPC_CACHE)).thenReturn(false); + + when(clusterService.createCache(RoutingTableImpl.RPC_CACHE, + EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))). + thenReturn(mockRpcCache); + + doNothing().when(clusterService).tbegin(); + doNothing().when(clusterService).tcommit(); + + routingTable.setClusterGlobalServices(this.clusterService); + routingTable.init(c); + + Assert.assertEquals(mockGlobalRpcCache, routingTable.getGlobalRpcCache()); + Assert.assertEquals(mockRpcCache, routingTable.getRpcCache()); + } + + private RpcRouter.RouteIdentifier getRouteIdentifier(){ + RpcRouter.RouteIdentifier routeIdentifier = mock(RpcRouter.RouteIdentifier.class); + InstanceIdentifier identifier = mock(InstanceIdentifier.class); + when(routeIdentifier.getType()).thenReturn(QNAME); + when(routeIdentifier.getRoute()).thenReturn(identifier); + + return routeIdentifier; + } + + private Runnable addRoutes(final int numRoutes, final String routePrefix, final RpcRouter.RouteIdentifier routeId){ + return new Runnable() { + @Override + public void run() { + for (int i=0;i, 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/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index 28ffff8b2d..ad4a1ee200 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -19,7 +19,6 @@ org.opendaylight.yangtools yang-maven-plugin - ${yangtools.version} @@ -51,7 +50,7 @@ org.opendaylight.controller yang-jmx-generator-plugin - 0.2.4-SNAPSHOT + ${config.version} org.opendaylight.yangtools 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-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java index e48ebbc057..e6e935c920 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java @@ -202,6 +202,16 @@ public class BindingIndependentConnector implements // DataModification, DataObject> source) { DataModificationTransaction target = biDataService.beginTransaction(); LOG.debug("Created DOM Transaction {} for {},", target.getIdentifier(),source.getIdentifier()); + for (InstanceIdentifier entry : source.getRemovedConfigurationData()) { + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry); + target.removeConfigurationData(biEntry); + LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry); + } + for (InstanceIdentifier entry : source.getRemovedOperationalData()) { + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry); + target.removeOperationalData(biEntry); + LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry); + } for (Entry, DataObject> entry : source.getUpdatedConfigurationData() .entrySet()) { Entry biEntry = mappingService @@ -216,16 +226,7 @@ public class BindingIndependentConnector implements // target.putOperationalData(biEntry.getKey(), biEntry.getValue()); LOG.debug("Update of Binding Operational Data {} is translated to {}",entry,biEntry); } - for (InstanceIdentifier entry : source.getRemovedConfigurationData()) { - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry); - target.removeConfigurationData(biEntry); - LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry); - } - for (InstanceIdentifier entry : source.getRemovedOperationalData()) { - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry); - target.removeOperationalData(biEntry); - LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry); - } + return target; } @@ -233,6 +234,24 @@ public class BindingIndependentConnector implements // DataModification source) { org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService .beginTransaction(); + for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) { + try { + + InstanceIdentifier baEntry = mappingService.fromDataDom(entry); + target.removeConfigurationData(baEntry); + } catch (DeserializationException e) { + LOG.error("Ommiting from BA transaction: {}.", entry, e); + } + } + for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) { + try { + + InstanceIdentifier baEntry = mappingService.fromDataDom(entry); + target.removeOperationalData(baEntry); + } catch (DeserializationException e) { + LOG.error("Ommiting from BA transaction: {}.", entry, e); + } + } for (Entry entry : source .getUpdatedConfigurationData().entrySet()) { try { @@ -254,24 +273,6 @@ public class BindingIndependentConnector implements // LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e); } } - for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) { - try { - - InstanceIdentifier baEntry = mappingService.fromDataDom(entry); - target.removeConfigurationData(baEntry); - } catch (DeserializationException e) { - LOG.error("Ommiting from BA transaction: {}.", entry, e); - } - } - for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) { - try { - - InstanceIdentifier baEntry = mappingService.fromDataDom(entry); - target.removeOperationalData(baEntry); - } catch (DeserializationException e) { - LOG.error("Ommiting from BA transaction: {}.", entry, e); - } - } return target; } diff --git a/opendaylight/md-sal/sal-binding-config/pom.xml b/opendaylight/md-sal/sal-binding-config/pom.xml index cb71b4fd3a..a58df8435b 100644 --- a/opendaylight/md-sal/sal-binding-config/pom.xml +++ b/opendaylight/md-sal/sal-binding-config/pom.xml @@ -24,7 +24,6 @@ org.opendaylight.yangtools yang-maven-plugin - ${yangtools.version} @@ -64,12 +63,12 @@ org.opendaylight.controller yang-jmx-generator-plugin - 0.2.4-SNAPSHOT + ${config.version} org.opendaylight.yangtools maven-sal-api-gen-plugin - ${yangtools.version} + ${yangtools.version} jar 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-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Futures.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Futures.java index 42b00ba03d..3384e8fb20 100644 --- a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Futures.java +++ b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Futures.java @@ -12,6 +12,10 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +/** + * @deprecated Use {@link com.google.common.util.concurrent.Futures} instead. + */ +@Deprecated public class Futures { private Futures() { diff --git a/opendaylight/md-sal/sal-dom-api/pom.xml b/opendaylight/md-sal/sal-dom-api/pom.xml index 9c253eecb8..9eadce3ed7 100644 --- a/opendaylight/md-sal/sal-dom-api/pom.xml +++ b/opendaylight/md-sal/sal-dom-api/pom.xml @@ -22,7 +22,6 @@ org.opendaylight.yangtools yang-maven-plugin - ${yangtools.version} @@ -54,7 +53,7 @@ org.opendaylight.controller yang-jmx-generator-plugin - 0.2.4-SNAPSHOT + ${config.version} org.opendaylight.yangtools 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/RoutedRpcDefaultImplementation.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RoutedRpcDefaultImplementation.java new file mode 100644 index 0000000000..c8eb7fd56f --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RoutedRpcDefaultImplementation.java @@ -0,0 +1,12 @@ +package org.opendaylight.controller.sal.core.api; + +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; + +public interface RoutedRpcDefaultImplementation { + + public RpcResult invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input); + +} 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-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java index 8a9d167865..f43dcd6b43 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java @@ -42,4 +42,13 @@ public interface RpcProvisionRegistry extends RpcImplementation, BrokerService, ListenerRegistration addRpcRegistrationListener(RpcRegistrationListener listener); RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation); + + /** + * Sets this RoutedRpc Implementation as a delegate rpc provider and will be asked to invoke rpc if the + * current provider can't service the rpc request + * + * @param defaultImplementation + * Provider's implementation of RPC functionality + */ + public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation); } diff --git a/opendaylight/md-sal/sal-dom-broker/pom.xml b/opendaylight/md-sal/sal-dom-broker/pom.xml index d22b54ee19..225281e7a4 100644 --- a/opendaylight/md-sal/sal-dom-broker/pom.xml +++ b/opendaylight/md-sal/sal-dom-broker/pom.xml @@ -63,7 +63,6 @@ org.opendaylight.yangtools yang-maven-plugin - ${yangtools.version} @@ -95,7 +94,7 @@ org.opendaylight.controller yang-jmx-generator-plugin - 0.2.4-SNAPSHOT + ${config.version} org.opendaylight.yangtools diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend index 1159d5650e..6b5f5acb19 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend @@ -50,7 +50,7 @@ class BrokerConfigActivator implements AutoCloseable { broker.setRouter(new SchemaAwareRpcBroker("/", SchemaContextProviders.fromSchemaService(schemaService))); dataService = new DataBrokerImpl(); - dataService.setExecutor(broker.getExecutor()); + //dataService.setExecutor(broker.getExecutor()); dataReg = context.registerService(DataBrokerService, dataService, emptyProperties); dataProviderReg = context.registerService(DataProviderService, dataService, emptyProperties); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend index 3bbdab2c07..64de8683d1 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend @@ -14,21 +14,22 @@ import java.util.concurrent.Callable import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import java.util.concurrent.Future -import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener import org.opendaylight.controller.sal.core.api.Broker import org.opendaylight.controller.sal.core.api.Consumer import org.opendaylight.controller.sal.core.api.Provider -import org.opendaylight.controller.sal.core.api.RpcImplementation -import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry -import org.opendaylight.controller.sal.core.api.RpcRegistrationListener -import org.opendaylight.controller.sal.core.api.RpcRoutingContext -import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter 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.osgi.framework.BundleContext import org.slf4j.LoggerFactory +import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter +import org.opendaylight.controller.sal.core.api.RpcRegistrationListener +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry +import org.opendaylight.controller.sal.core.api.RpcImplementation +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener +import org.opendaylight.controller.sal.core.api.RpcRoutingContext +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier +import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable { private static val log = LoggerFactory.getLogger(BrokerImpl); @@ -122,7 +123,11 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable { override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { router.addRoutedRpcImplementation(rpcType,implementation); } - + + override setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation) { + router.setRoutedRpcDefaultDelegate(defaultImplementation); + } + override addRpcRegistrationListener(RpcRegistrationListener listener) { return router.addRpcRegistrationListener(listener); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java index a8bdddb510..5d93f4ee4d 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java @@ -19,6 +19,7 @@ import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener import org.opendaylight.controller.sal.common.DataStoreIdentifier; import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration; import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration; +import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation; import org.opendaylight.controller.sal.core.api.RpcImplementation; import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; import org.opendaylight.controller.sal.core.api.RpcRoutingContext; @@ -104,6 +105,11 @@ public class MountPointImpl implements MountProvisionInstance, SchemaContextProv } @Override + public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation) { + rpcs.setRoutedRpcDefaultDelegate(defaultImplementation); + } + + @Override public RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException { return rpcs.addRpcImplementation(rpcType, implementation); 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..d8315568be 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 @@ -11,6 +11,9 @@ import static com.google.common.base.Preconditions.checkState; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Future; @@ -27,11 +30,13 @@ 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.Node; +import org.opendaylight.yangtools.yang.data.api.SimpleNode; import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; +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; @@ -41,7 +46,6 @@ import com.google.common.collect.ImmutableSet; public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator implements // DataStore, // - SchemaServiceListener, // SchemaContextListener, // AutoCloseable { @@ -168,18 +172,25 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator original) { NormalizedDataModification normalized = new NormalizedDataModification(original); - for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { - normalized.putConfigurationData(entry.getKey(), entry.getValue()); - } - for (Entry entry : original.getUpdatedOperationalData().entrySet()) { - normalized.putOperationalData(entry.getKey(), entry.getValue()); - } + LOG.trace("Transaction: {} Removed Configuration {}, Removed Operational {}", original.getIdentifier(), + original.getRemovedConfigurationData(), original.getRemovedConfigurationData()); + LOG.trace("Transaction: {} Created Configuration {}, Created Operational {}", original.getIdentifier(), + original.getCreatedConfigurationData().entrySet(), original.getCreatedOperationalData().entrySet()); + LOG.trace("Transaction: {} Updated Configuration {}, Updated Operational {}", original.getIdentifier(), + original.getUpdatedConfigurationData().entrySet(), original.getUpdatedOperationalData().entrySet()); + for (InstanceIdentifier entry : original.getRemovedConfigurationData()) { normalized.deepRemoveConfigurationData(entry); } for (InstanceIdentifier entry : original.getRemovedOperationalData()) { normalized.deepRemoveOperationalData(entry); } + for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { + normalized.putDeepConfigurationData(entry.getKey(), entry.getValue()); + } + for (Entry entry : original.getUpdatedOperationalData().entrySet()) { + normalized.putDeepOperationalData(entry.getKey(), entry.getValue()); + } return normalized; } @@ -310,6 +321,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 +355,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-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java index 28d5ae914f..22319abb17 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java @@ -19,6 +19,7 @@ import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils; import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration; import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration; +import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation; import org.opendaylight.controller.sal.core.api.RpcImplementation; import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; import org.opendaylight.controller.sal.core.api.RpcRoutingContext; @@ -44,7 +45,7 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.collect.ImmutableSet; -public class SchemaAwareRpcBroker implements RpcRouter, Identifiable { +public class SchemaAwareRpcBroker implements RpcRouter, Identifiable, RoutedRpcDefaultImplementation { private static final Logger LOG = LoggerFactory.getLogger(SchemaAwareRpcBroker.class); @@ -58,6 +59,7 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable { private final ConcurrentMap implementations = new ConcurrentHashMap<>(); private RpcImplementation defaultImplementation; private SchemaContextProvider schemaProvider; + private RoutedRpcDefaultImplementation defaultDelegate; public SchemaAwareRpcBroker(String identifier, SchemaContextProvider schemaProvider) { super(); @@ -81,7 +83,16 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable { this.schemaProvider = schemaProvider; } + public RoutedRpcDefaultImplementation getRoutedRpcDefaultDelegate() { + return defaultDelegate; + } + @Override + public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultDelegate) { + this.defaultDelegate = defaultDelegate; + } + + @Override public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { checkArgument(rpcType != null, "RPC Type should not be null"); checkArgument(implementation != null, "RPC Implementatoin should not be null"); @@ -221,6 +232,12 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable { return ret; } + @Override + public RpcResult invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) { + checkState(defaultDelegate != null); + return defaultDelegate.invokeRpc(rpc, identifier, input); + } + private static abstract class RoutingStrategy implements Identifiable { private final QName identifier; @@ -304,6 +321,7 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable { SimpleNode routeContainer = inputContainer.getFirstSimpleByName(strategy.getLeaf()); checkArgument(routeContainer != null, "Leaf %s must be set with value", strategy.getLeaf()); Object route = routeContainer.getValue(); + checkArgument(route instanceof InstanceIdentifier); RpcImplementation potential = null; if (route != null) { RoutedRpcRegImpl potentialReg = implementations.get(route); @@ -312,7 +330,7 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable { } } if (potential == null) { - potential = defaultDelegate; + return router.invokeRpc(rpc, (InstanceIdentifier) route, input); } checkState(potential != null, "No implementation is available for rpc:%s path:%s", rpc, route); return potential.invokeRpc(rpc, input); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java index e218a95782..40842c004a 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java @@ -9,11 +9,7 @@ package org.opendaylight.controller.sal.dom.broker.osgi; import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; -import org.opendaylight.controller.sal.core.api.Broker; -import org.opendaylight.controller.sal.core.api.RpcImplementation; -import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; -import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; -import org.opendaylight.controller.sal.core.api.RpcRoutingContext; +import org.opendaylight.controller.sal.core.api.*; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; @@ -45,7 +41,12 @@ public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy> ListenerRegistration registerRouteChangeListener(L listener) { return getDelegate().registerRouteChangeListener(listener); } diff --git a/opendaylight/md-sal/sal-netconf-connector/pom.xml b/opendaylight/md-sal/sal-netconf-connector/pom.xml index b060ca42d0..289afbbce3 100644 --- a/opendaylight/md-sal/sal-netconf-connector/pom.xml +++ b/opendaylight/md-sal/sal-netconf-connector/pom.xml @@ -5,9 +5,7 @@ sal-parent 1.1-SNAPSHOT - - 0.2.4-SNAPSHOT - + sal-netconf-connector scm:git:ssh://git.opendaylight.org:29418/controller.git @@ -202,7 +200,6 @@ org.opendaylight.yangtools yang-maven-plugin - ${yangtools.version} @@ -234,12 +231,12 @@ org.opendaylight.controller yang-jmx-generator-plugin - 0.2.4-SNAPSHOT + ${config.version} org.opendaylight.yangtools maven-sal-api-gen-plugin - ${yangtools.version} + ${yangtools.version} jar diff --git a/opendaylight/md-sal/sal-remote/pom.xml b/opendaylight/md-sal/sal-remote/pom.xml index d4f5d43e5e..b0424f945b 100644 --- a/opendaylight/md-sal/sal-remote/pom.xml +++ b/opendaylight/md-sal/sal-remote/pom.xml @@ -30,7 +30,6 @@ org.opendaylight.yangtools yang-maven-plugin - ${yangtools.version} sal-remote diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java index 95bb62f93b..d874381ab3 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.config.yang.md.sal.remote.rpc; import org.opendaylight.controller.sal.connector.remoterpc.*; import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.osgi.framework.BundleContext; /** @@ -46,17 +47,18 @@ public final class ZeroMQServerModule extends org.opendaylight.controller.config ClientImpl clientImpl = new ClientImpl(); - RoutingTableProvider provider = new RoutingTableProvider(bundleContext,serverImpl); + RoutingTableProvider provider = new RoutingTableProvider(bundleContext);//,serverImpl); - RemoteRpcProvider facade = new RemoteRpcProvider(serverImpl, clientImpl); - - facade.setRoutingTableProvider(provider ); - - broker.registerProvider(facade, bundleContext); - return facade; - } - public void setBundleContext(BundleContext bundleContext) { - this.bundleContext = bundleContext; - } + facade.setRoutingTableProvider(provider ); + facade.setContext(bundleContext); + facade.setRpcProvisionRegistry((RpcProvisionRegistry) broker); + + broker.registerProvider(facade, bundleContext); + return facade; + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ClientImpl.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ClientImpl.java index 291fe0b8e7..30e11c0806 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ClientImpl.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ClientImpl.java @@ -12,6 +12,8 @@ import org.opendaylight.controller.sal.common.util.RpcErrors; import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.controller.sal.connector.api.RpcRouter; import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable; +import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException; +import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException; import org.opendaylight.controller.sal.connector.remoterpc.dto.Message; import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl; import org.opendaylight.controller.sal.connector.remoterpc.util.XmlUtils; @@ -20,14 +22,13 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcError; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.zeromq.ZMQ; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; @@ -66,12 +67,6 @@ public class ClientImpl implements RemoteRpcClient { this.routingTableProvider = routingTableProvider; } - @Override - public Set getSupportedRpcs(){ - //TODO: Find the entries from routing table - return Collections.emptySet(); - } - @Override public void start() {/*NOOPS*/} @@ -97,14 +92,40 @@ public class ClientImpl implements RemoteRpcClient { * @param input payload for the remote service * @return */ - @Override public RpcResult invokeRpc(QName rpc, CompositeNode input) { + RouteIdentifierImpl routeId = new RouteIdentifierImpl(); + routeId.setType(rpc); + + String address = lookupRemoteAddressForGlobalRpc(routeId); + return sendMessage(input, routeId, address); + } + + /** + * Finds remote server that can execute this routed rpc and sends a message to it + * requesting execution. + * The call blocks until a response from remote server is received. Its upto + * the client of this API to implement a timeout functionality. + * + * @param rpc + * rpc to be called + * @param identifier + * instance identifier on which rpc is to be executed + * @param input + * payload + * @return + */ + public RpcResult invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) { RouteIdentifierImpl routeId = new RouteIdentifierImpl(); routeId.setType(rpc); + routeId.setRoute(identifier); + + String address = lookupRemoteAddressForRpc(routeId); - String address = lookupRemoteAddress(routeId); + return sendMessage(input, routeId, address); + } + private RpcResult sendMessage(CompositeNode input, RouteIdentifierImpl routeId, String address) { Message request = new Message.MessageBuilder() .type(Message.MessageType.REQUEST) .sender(Context.getInstance().getLocalUri()) @@ -128,7 +149,6 @@ public class ClientImpl implements RemoteRpcClient { collectErrors(e, errors); return Rpcs.getRpcResult(false, null, errors); } - } /** @@ -136,19 +156,36 @@ public class ClientImpl implements RemoteRpcClient { * @param routeId route identifier * @return remote network address */ - private String lookupRemoteAddress(RpcRouter.RouteIdentifier routeId){ + private String lookupRemoteAddressForGlobalRpc(RpcRouter.RouteIdentifier routeId){ checkNotNull(routeId, "route must not be null"); - Optional> routingTable = routingTableProvider.getRoutingTable(); + Optional> routingTable = routingTableProvider.getRoutingTable(); checkNotNull(routingTable.isPresent(), "Routing table is null"); - Set addresses = routingTable.get().getRoutes(routeId.toString()); - checkNotNull(addresses, "Address not found for route [%s]", routeId); - checkState(addresses.size() == 1, - "Multiple remote addresses found for route [%s], \nonly 1 expected", routeId); //its a global service. + String address = null; + try { + address = routingTable.get().getGlobalRoute(routeId); + } catch (RoutingTableException|SystemException e) { + _logger.error("Exception caught while looking up remote address " + e); + } + checkState(address != null, "Address not found for route [%s]", routeId); + + return address; + } + + /** + * Find address for the given route identifier in routing table + * @param routeId route identifier + * @return remote network address + */ + private String lookupRemoteAddressForRpc(RpcRouter.RouteIdentifier routeId){ + checkNotNull(routeId, "route must not be null"); + + Optional> routingTable = routingTableProvider.getRoutingTable(); + checkNotNull(routingTable.isPresent(), "Routing table is null"); - String address = addresses.iterator().next(); - checkNotNull(address, "Address not found for route [%s]", routeId); + String address = routingTable.get().getLastAddedRoute(routeId); + checkState(address != null, "Address not found for route [%s]", routeId); return address; } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcClient.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcClient.java index 1f78a6771a..a564a0ad04 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcClient.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcClient.java @@ -9,9 +9,9 @@ package org.opendaylight.controller.sal.connector.remoterpc; import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation; -public interface RemoteRpcClient extends RpcImplementation,AutoCloseable{ - +public interface RemoteRpcClient extends AutoCloseable{ void setRoutingTableProvider(RoutingTableProvider provider); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProvider.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProvider.java index bf205fc38d..639e31ddc3 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProvider.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProvider.java @@ -8,86 +8,289 @@ package org.opendaylight.controller.sal.connector.remoterpc; +import com.google.common.base.Optional; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.sal.connector.api.RpcRouter; +import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable; +import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException; +import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException; +import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; import org.opendaylight.controller.sal.core.api.Provider; +import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; +import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; +import org.opendaylight.controller.sal.core.api.RpcRoutingContext; 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.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; import java.util.Set; -public class RemoteRpcProvider implements - RemoteRpcServer, - RemoteRpcClient, +import static com.google.common.base.Preconditions.checkNotNull; + +public class RemoteRpcProvider implements + RpcImplementation, + RoutedRpcDefaultImplementation, + AutoCloseable, Provider { - private final ServerImpl server; - private final ClientImpl client; - private RoutingTableProvider provider; + private Logger _logger = LoggerFactory.getLogger(RemoteRpcProvider.class); - @Override - public void setRoutingTableProvider(RoutingTableProvider provider) { - this.provider = provider; - server.setRoutingTableProvider(provider); - client.setRoutingTableProvider(provider); + private final ServerImpl server; + private final ClientImpl client; + private RoutingTableProvider routingTableProvider; + private final RpcListener listener = new RpcListener(); + private final RoutedRpcListener routeChangeListener = new RoutedRpcListener(); + private ProviderSession brokerSession; + private RpcProvisionRegistry rpcProvisionRegistry; + private BundleContext context; + private ServiceTracker clusterTracker; + + public RemoteRpcProvider(ServerImpl server, ClientImpl client) { + this.server = server; + this.client = client; + } + + public void setRoutingTableProvider(RoutingTableProvider provider) { + this.routingTableProvider = provider; + client.setRoutingTableProvider(provider); + } + + public void setContext(BundleContext context){ + this.context = context; + } + + public void setRpcProvisionRegistry(RpcProvisionRegistry rpcProvisionRegistry){ + this.rpcProvisionRegistry = rpcProvisionRegistry; + } + + @Override + public void onSessionInitiated(ProviderSession session) { + brokerSession = session; + server.setBrokerSession(session); + start(); + } + + @Override + public Set getSupportedRpcs() { + //TODO: Ask Tony if we need to get this from routing table + return Collections.emptySet(); + } + + @Override + public Collection getProviderFunctionality() { + // TODO Auto-generated method stub + return null; + } + + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode input) { + return client.invokeRpc(rpc, input); + } + + @Override + public RpcResult invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) { + return client.invokeRpc(rpc, identifier, input); + } + + public void start() { + server.start(); + client.start(); + brokerSession.addRpcRegistrationListener(listener); + rpcProvisionRegistry.setRoutedRpcDefaultDelegate(this); + rpcProvisionRegistry.registerRouteChangeListener(routeChangeListener); + + announceSupportedRpcs(); + announceSupportedRoutedRpcs(); + } + + @Override + public void close() throws Exception { + unregisterSupportedRpcs(); + unregisterSupportedRoutedRpcs(); + server.close(); + client.close(); + } + + public void stop() { + server.stop(); + client.stop(); + } + + /** + * Add all the locally registered RPCs in the clustered routing table + */ + private void announceSupportedRpcs(){ + Set currentlySupported = brokerSession.getSupportedRpcs(); + for (QName rpc : currentlySupported) { + listener.onRpcImplementationAdded(rpc); } - - @Override - public RpcResult invokeRpc(QName rpc, CompositeNode input) { - return client.invokeRpc(rpc, input); + } + + /** + * Add all the locally registered Routed RPCs in the clustered routing table + */ + private void announceSupportedRoutedRpcs(){ + + //TODO: announce all routed RPCs as well + + } + + /** + * Un-Register all the supported RPCs from clustered routing table + */ + private void unregisterSupportedRpcs(){ + Set currentlySupported = brokerSession.getSupportedRpcs(); + //TODO: remove all routed RPCs as well + for (QName rpc : currentlySupported) { + listener.onRpcImplementationRemoved(rpc); } - + } + + /** + * Un-Register all the locally supported Routed RPCs from clustered routing table + */ + private void unregisterSupportedRoutedRpcs(){ + + //TODO: remove all routed RPCs as well + + } + + private RoutingTable getRoutingTable(){ + Optional> routingTable = + routingTableProvider.getRoutingTable(); + + checkNotNull(routingTable.isPresent(), "Routing table is null"); + + return routingTable.get(); + } + + /** + * Listener for rpc registrations in broker + */ + private class RpcListener implements RpcRegistrationListener { + @Override - public Set getSupportedRpcs() { - return client.getSupportedRpcs(); - } - - - public RemoteRpcProvider(ServerImpl server, ClientImpl client) { - this.server = server; - this.client = client; - } - - public void setBrokerSession(ProviderSession session) { - server.setBrokerSession(session); - } -// public void setServerPool(ExecutorService serverPool) { -// server.setServerPool(serverPool); -// } - public void start() { - //when listener was being invoked and addRPCImplementation was being - //called the client was null. - server.setClient(client); - server.start(); - client.start(); + public void onRpcImplementationAdded(QName rpc) { + + _logger.debug("Adding registration for [{}]", rpc); + RouteIdentifierImpl routeId = new RouteIdentifierImpl(); + routeId.setType(rpc); + RoutingTable routingTable = getRoutingTable(); + try { + routingTable.addGlobalRoute(routeId, server.getServerAddress()); + _logger.debug("Route added [{}-{}]", routeId, server.getServerAddress()); + + } catch (RoutingTableException | SystemException e) { + //TODO: This can be thrown when route already exists in the table. Broker + //needs to handle this. + _logger.error("Unhandled exception while adding global route to routing table [{}]", e); + + } } - @Override - public Collection getProviderFunctionality() { - // TODO Auto-generated method stub - return null; + public void onRpcImplementationRemoved(QName rpc) { + + _logger.debug("Removing registration for [{}]", rpc); + RouteIdentifierImpl routeId = new RouteIdentifierImpl(); + routeId.setType(rpc); + + RoutingTable routingTable = getRoutingTable(); + + try { + routingTable.removeGlobalRoute(routeId); + } catch (RoutingTableException | SystemException e) { + _logger.error("Route delete failed {}", e); + } } - - + } + + /** + * Listener for Routed Rpc registrations in broker + */ + private class RoutedRpcListener + implements RouteChangeListener { + + /** + * + * @param routeChange + */ @Override - public void onSessionInitiated(ProviderSession session) { - server.setBrokerSession(session); - start(); + public void onRouteChange(RouteChange routeChange) { + Map> announcements = routeChange.getAnnouncements(); + announce(getRouteIdentifiers(announcements)); + + Map> removals = routeChange.getRemovals(); + remove(getRouteIdentifiers(removals)); + } + + /** + * + * @param announcements + */ + private void announce(Set announcements) { + _logger.debug("Announcing [{}]", announcements); + RoutingTable routingTable = getRoutingTable(); + try { + routingTable.addRoutes(announcements, server.getServerAddress()); + } catch (RoutingTableException | SystemException e) { + _logger.error("Route announcement failed {}", e); + } } - - - public void close() throws Exception { - server.close(); - client.close(); + + /** + * + * @param removals + */ + private void remove(Set removals){ + _logger.debug("Removing [{}]", removals); + RoutingTable routingTable = getRoutingTable(); + try { + routingTable.removeRoutes(removals, server.getServerAddress()); + } catch (RoutingTableException | SystemException e) { + _logger.error("Route removal failed {}", e); + } } - @Override - public void stop() { - server.stop(); - client.stop(); + /** + * + * @param changes + * @return + */ + private Set getRouteIdentifiers(Map> changes) { + RouteIdentifierImpl routeId = null; + Set routeIdSet = new HashSet(); + + for (RpcRoutingContext context : changes.keySet()){ + routeId = new RouteIdentifierImpl(); + routeId.setType(context.getRpc()); + routeId.setContext(context.getContext()); + + for (InstanceIdentifier instanceId : changes.get(context)){ + routeId.setRoute(instanceId); + routeIdSet.add(routeId); + } + } + return routeIdSet; } + + + + } + } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RoutingTableProvider.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RoutingTableProvider.java index f62c26e0fd..71bab288e6 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RoutingTableProvider.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RoutingTableProvider.java @@ -9,8 +9,10 @@ package org.opendaylight.controller.sal.connector.remoterpc; import com.google.common.base.Optional; +import org.opendaylight.controller.sal.connector.api.RpcRouter; import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener; import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable; +import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl; import org.opendaylight.controller.sal.connector.remoterpc.impl.RoutingTableImpl; import org.osgi.framework.BundleContext; import org.osgi.util.tracker.ServiceTracker; @@ -22,26 +24,26 @@ public class RoutingTableProvider implements AutoCloseable { private RoutingTableImpl routingTableImpl = null; - final private RouteChangeListener routeChangeListener; + //final private RouteChangeListener routeChangeListener; - public RoutingTableProvider(BundleContext ctx,RouteChangeListener rcl) { + public RoutingTableProvider(BundleContext ctx){//,RouteChangeListener rcl) { @SuppressWarnings("rawtypes") ServiceTracker rawTracker = new ServiceTracker<>(ctx, RoutingTable.class, null); tracker = rawTracker; tracker.open(); - routeChangeListener = rcl; + //routeChangeListener = rcl; } - public Optional> getRoutingTable() { + public Optional> getRoutingTable() { @SuppressWarnings("unchecked") - RoutingTable tracked = tracker.getService(); + RoutingTable tracked = tracker.getService(); if(tracked instanceof RoutingTableImpl){ if(routingTableImpl != tracked){ routingTableImpl= (RoutingTableImpl)tracked; - routingTableImpl.setRouteChangeListener(routeChangeListener); + //routingTableImpl.setRouteChangeListener(routeChangeListener); } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java index 5c14dd0c45..722ca06879 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java @@ -18,6 +18,7 @@ import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableExcep import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException; import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; import org.opendaylight.controller.sal.core.api.RpcRoutingContext; import org.opendaylight.yangtools.yang.common.QName; @@ -43,10 +44,9 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; /** - * ZeroMq based implementation of RpcRouter. It implements RouteChangeListener of RoutingTable - * so that it gets route change notifications from routing table. + * ZeroMq based implementation of RpcRouter. */ -public class ServerImpl implements RemoteRpcServer, RouteChangeListener { +public class ServerImpl implements RemoteRpcServer { private Logger _logger = LoggerFactory.getLogger(ServerImpl.class); @@ -57,8 +57,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener();// serverPool = Executors.newSingleThreadExecutor();//main server thread serverPool.execute(receive()); // Start listening rpc requests - brokerSession.addRpcRegistrationListener(listener); - - announceLocalRpcs(); - - registerRemoteRpcs(); status = State.STARTED; _logger.info("Remote RPC Server started [{}]", getServerAddress()); @@ -179,8 +152,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener> routingTableOptional = routingTableProvider.getRoutingTable(); - - Preconditions.checkState(routingTableOptional.isPresent(), "Routing table is absent"); - - Set remoteRoutes = - routingTableProvider.getRoutingTable().get().getAllRoutes(); - - //filter out all entries that contains local address - //we dont want to register local RPCs as remote - Predicate notLocalAddressFilter = new Predicate(){ - public boolean apply(Map.Entry remoteRoute){ - return !getServerAddress().equalsIgnoreCase((String)remoteRoute.getValue()); - } - }; - - //filter the entries created by current node - Set filteredRemoteRoutes = Sets.filter(remoteRoutes, notLocalAddressFilter); - - for (Map.Entry route : filteredRemoteRoutes){ - onRouteUpdated((String) route.getKey(), "");//value is not needed by broker - } - } - - /** - * Un-Register the local RPCs from the routing table - */ - private void unregisterLocalRpcs(){ - Set currentlySupported = brokerSession.getSupportedRpcs(); - for (QName rpc : currentlySupported) { - listener.onRpcImplementationRemoved(rpc); - } - } - - /** - * Publish all the locally registered RPCs in the routing table - */ - private void announceLocalRpcs(){ - Set currentlySupported = brokerSession.getSupportedRpcs(); - for (QName rpc : currentlySupported) { - listener.onRpcImplementationAdded(rpc); - } - } - - /** - * @param key - * @param value - */ - @Override - public void onRouteUpdated(String key, String value) { - RouteIdentifierImpl rId = new RouteIdentifierImpl(); - try { - _logger.debug("Updating key/value {}-{}", key, value); - brokerSession.addRpcImplementation( - (QName) rId.fromString(key).getType(), client); - - //TODO: Check with Tony for routed rpc - //brokerSession.addRoutedRpcImplementation((QName) rId.fromString(key).getRoute(), client); - } catch (Exception e) { - _logger.info("Route update failed {}", e); - } - } - - /** - * @param key - */ - @Override - public void onRouteDeleted(String key) { - //TODO: Broker session needs to be updated to support this - throw new UnsupportedOperationException(); - } - /** * Finds IPv4 address of the local VM * TODO: This method is non-deterministic. There may be more than one IPv4 address. Cant say which @@ -381,74 +277,4 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener routingTable = getRoutingTable(); - - try { - routingTable.addGlobalRoute(routeId.toString(), getServerAddress()); - _logger.debug("Route added [{}-{}]", name, getServerAddress()); - - } catch (RoutingTableException | SystemException e) { - //TODO: This can be thrown when route already exists in the table. Broker - //needs to handle this. - _logger.error("Unhandled exception while adding global route to routing table [{}]", e); - - } - } - - @Override - public void onRpcImplementationRemoved(QName name) { - - _logger.debug("Removing registration for [{}]", name); - RouteIdentifierImpl routeId = new RouteIdentifierImpl(); - routeId.setType(name); - - RoutingTable routingTable = getRoutingTable(); - - try { - routingTable.removeGlobalRoute(routeId.toString()); - } catch (RoutingTableException | SystemException e) { - _logger.error("Route delete failed {}", e); - } - } - - private RoutingTable getRoutingTable(){ - Optional> routingTable = - routingTableProvider.getRoutingTable(); - - checkNotNull(routingTable.isPresent(), "Routing table is null"); - - return routingTable.get(); - } - } - - /* - * Listener for Route changes in broker. Broker notifies this listener in the event - * of any change (add/delete). Listener then updates the routing table. - */ - private class BrokerRouteChangeListener - implements org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener{ - - @Override - public void onRouteChange(RouteChange routeChange) { - - } - } - } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/RouteIdentifierImpl.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/RouteIdentifierImpl.java index 06107a8773..ec6a1a94b6 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/RouteIdentifierImpl.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/RouteIdentifierImpl.java @@ -18,8 +18,6 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier,Serializable { - transient ObjectMapper mapper = new ObjectMapper(); - private QName context; private QName type; private InstanceIdentifier route; @@ -50,38 +48,4 @@ public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier mockRoutingTable = new MockRoutingTable(); - Optional> optionalRoutingTable = Optional.fromNullable(mockRoutingTable); + RoutingTable mockRoutingTable = new MockRoutingTable(); + Optional> optionalRoutingTable = Optional.fromNullable(mockRoutingTable); when(routingTableProvider.getRoutingTable()).thenReturn(optionalRoutingTable); //mock ClientRequestHandler @@ -81,7 +82,7 @@ public class ClientImplTest { } - @Test + //@Test public void invokeRpc_NormalCall_ShouldReturnSuccess() throws Exception { when(mockHandler.handle(any(Message.class))). @@ -94,7 +95,7 @@ public class ClientImplTest { Assert.assertNull(result.getResult()); } - @Test + //@Test public void invokeRpc_HandlerThrowsException_ShouldReturnError() throws Exception { when(mockHandler.handle(any(Message.class))). diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/MockRoutingTable.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/MockRoutingTable.java index 9c74be93bd..0fe0155bb6 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/MockRoutingTable.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/MockRoutingTable.java @@ -38,11 +38,26 @@ public class MockRoutingTable implements RoutingTable { } + @Override + public void addRoutes(Set set, Object o) throws RoutingTableException, SystemException { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void removeRoutes(Set set, Object o) throws RoutingTableException, SystemException { + //To change body of implemented methods use File | Settings | File Templates. + } + @Override public void removeGlobalRoute(Object o) throws RoutingTableException, SystemException { } + @Override + public Object getGlobalRoute(Object o) throws RoutingTableException, SystemException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + @Override public Set getRoutes(Object o) { Set routes = new HashSet(); @@ -51,17 +66,17 @@ public class MockRoutingTable implements RoutingTable { } @Override - public Set getAllRoutes() { - return Collections.emptySet(); + public Object getLastAddedRoute(Object o) { + return null; //To change body of implemented methods use File | Settings | File Templates. } - @Override - public Object getARoute(Object o) { - return null; - } +// @Override +// public Set getAllRoutes() { +// return Collections.emptySet(); +// } - @Override - public void registerRouteChangeListener(RouteChangeListener routeChangeListener) { - - } +// @Override +// public Object getARoute(Object o) { +// return null; +// } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProviderTest.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProviderTest.java new file mode 100644 index 0000000000..06360aa7b3 --- /dev/null +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProviderTest.java @@ -0,0 +1,62 @@ +package org.opendaylight.controller.sal.connector.remoterpc; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class RemoteRpcProviderTest { + @Before + public void setUp() throws Exception { + + } + + @After + public void tearDown() throws Exception { + + } + + @Test + public void testSetRoutingTableProvider() throws Exception { + + } + + @Test + public void testOnSessionInitiated() throws Exception { + + } + + @Test + public void testGetSupportedRpcs() throws Exception { + + } + + @Test + public void testGetProviderFunctionality() throws Exception { + + } + + @Test + public void testInvokeRpc() throws Exception { + + } + + @Test + public void testInvokeRoutedRpc() throws Exception { + + } + + @Test + public void testStart() throws Exception { + + } + + @Test + public void testClose() throws Exception { + + } + + @Test + public void testStop() throws Exception { + + } +} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RouteIdentifierImplTest.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RouteIdentifierImplTest.java deleted file mode 100644 index 468d7829c4..0000000000 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RouteIdentifierImplTest.java +++ /dev/null @@ -1,62 +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.sal.connector.remoterpc; - -import java.net.URI; - -import com.fasterxml.jackson.core.JsonParseException; -import org.junit.Assert; -import org.junit.Test; -import org.opendaylight.controller.sal.connector.api.RpcRouter; -import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl; -import org.opendaylight.yangtools.yang.common.QName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RouteIdentifierImplTest { - - Logger _logger = LoggerFactory.getLogger(RouteIdentifierImplTest.class); - - private final URI namespace = URI.create("http://cisco.com/example"); - private final QName QNAME = new QName(namespace, "heartbeat"); - - @Test - public void testToString() throws Exception { - RouteIdentifierImpl rId = new RouteIdentifierImpl(); - rId.setType(QNAME); - - _logger.debug(rId.toString()); - - Assert.assertTrue(true); - - } - - @Test - public void testFromString() throws Exception { - RouteIdentifierImpl rId = new RouteIdentifierImpl(); - rId.setType(QNAME); - - String s = rId.toString(); - _logger.debug("serialized route: {}", s); - - RpcRouter.RouteIdentifier ref = new RouteIdentifierImpl().fromString(s); - _logger.debug("deserialized route: {}", ref); - - Assert.assertTrue(true); - } - - @Test(expected = JsonParseException.class) - public void testFromInvalidString() throws Exception { - String invalidInput = "aklhdgadfa;;;;;;;]]]]=]ag" ; - RouteIdentifierImpl rId = new RouteIdentifierImpl(); - rId.fromString(invalidInput); - - _logger.debug("" + rId); - Assert.assertTrue(true); - } -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImplTest.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImplTest.java index 1b282f6ab5..886ff426c7 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImplTest.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImplTest.java @@ -11,6 +11,7 @@ package org.opendaylight.controller.sal.connector.remoterpc; import com.google.common.base.Optional; import junit.framework.Assert; import org.junit.*; +import org.opendaylight.controller.sal.connector.api.RpcRouter; import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable; import org.opendaylight.controller.sal.connector.remoterpc.utils.MessagingUtil; import org.opendaylight.controller.sal.core.api.Broker; @@ -66,10 +67,9 @@ public class ServerImplTest { server = new ServerImpl(port); server.setBrokerSession(brokerSession); - server.setRoutingTableProvider(routingTableProvider); - RoutingTable mockRoutingTable = new MockRoutingTable(); - Optional> optionalRoutingTable = Optional.fromNullable(mockRoutingTable); + RoutingTable mockRoutingTable = new MockRoutingTable(); + Optional> optionalRoutingTable = Optional.fromNullable(mockRoutingTable); when(routingTableProvider.getRoutingTable()).thenReturn(optionalRoutingTable); when(brokerSession.addRpcRegistrationListener(listener)).thenReturn(null); @@ -94,11 +94,6 @@ public class ServerImplTest { Assert.assertEquals(ServerImpl.State.STOPPED, server.getStatus()); } - @Test - public void getRoutingTableProvider_Call_ShouldReturnRoutingTable() throws Exception { - Assert.assertNotNull(server.getRoutingTableProvider()); - } - @Test public void getBrokerSession_Call_ShouldReturnBrokerSession() throws Exception { Optional mayBeBroker = server.getBrokerSession(); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml index dc2fdbf9a0..a6bbe31684 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml @@ -24,14 +24,14 @@ com.sun.jersey.spi.container.servlet, - org.codehaus.jackson.annotate, + !org.codehaus.jackson.annotate, javax.ws.rs, javax.ws.rs.core, javax.xml.bind, javax.xml.bind.annotation, org.slf4j, org.apache.catalina.filters, - org.codehaus.jackson.jaxrs, + !org.codehaus.jackson.jaxrs, org.opendaylight.controller.sample.zeromq.provider, org.opendaylight.controller.sample.zeromq.consumer, org.opendaylight.controller.sal.utils, 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/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterActivator.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClient.java similarity index 55% rename from opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterActivator.java rename to opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClient.java index 7e6e7e5d75..0044d367f8 100644 --- a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterActivator.java +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClient.java @@ -5,8 +5,12 @@ * 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.sample.toaster.provider; +package org.opendaylight.controller.sal.restconf.broker.client; -public class ToasterActivator { +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/md-sal/samples/pom.xml b/opendaylight/md-sal/samples/pom.xml index a332ef77b6..54810266a7 100644 --- a/opendaylight/md-sal/samples/pom.xml +++ b/opendaylight/md-sal/samples/pom.xml @@ -1,3 +1,4 @@ + 4.0.0 @@ -18,7 +19,7 @@ toaster toaster-consumer toaster-provider - + @@ -27,10 +28,10 @@ false - + toaster-it org.opendaylight.controller.samples - + \ No newline at end of file diff --git a/opendaylight/md-sal/samples/toaster-consumer/pom.xml b/opendaylight/md-sal/samples/toaster-consumer/pom.xml index 40e99ec28b..fca9783f61 100644 --- a/opendaylight/md-sal/samples/toaster-consumer/pom.xml +++ b/opendaylight/md-sal/samples/toaster-consumer/pom.xml @@ -14,6 +14,12 @@ HEAD + + 1.1-SNAPSHOT + ${project.build.directory}/generated-sources/config + + + @@ -21,12 +27,69 @@ maven-bundle-plugin - org.opendaylight.controller.sample.toaster.provider.api - org.opendaylight.controller.sample.toaster.provider.impl - org.opendaylight.controller.sample.toaster.provider.impl.ToastConsumerImpl + + org.opendaylight.controller.sample.toaster.provider.api, + org.opendaylight.controller.config.yang.toaster-consumer, + + * + + org.opendaylight.yangtools + yang-maven-plugin + + + config + + generate-sources + + + + + + org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + + ${jmxGeneratorPath} + + + urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang + + + + + true + + + + + + org.opendaylight.controller + yang-jmx-generator-plugin + ${config.version} + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${jmxGeneratorPath} + + + + + @@ -40,5 +103,15 @@ org.opendaylight.controller sal-binding-api + + org.opendaylight.controller + config-api + ${config.version} + + + org.opendaylight.controller + sal-binding-config + ${sal-binding-api.version} + diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java new file mode 100644 index 0000000000..c006a34da7 --- /dev/null +++ b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java @@ -0,0 +1,68 @@ +/** +* Generated file + +* Generated from: yang module name: toaster-consumer-impl yang module local name: toaster-consumer-impl +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Feb 05 11:31:30 CET 2014 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.config.toaster_consumer.impl; + +import org.opendaylight.controller.sal.binding.api.NotificationListener; +import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer; +import org.opendaylight.controller.sample.toaster.provider.impl.ToastConsumerImpl; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService; +import org.opendaylight.yangtools.concepts.Registration; + +/** +* +*/ +public final class ToasterConsumerModule extends org.opendaylight.controller.config.yang.config.toaster_consumer.impl.AbstractToasterConsumerModule + { + + public ToasterConsumerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public ToasterConsumerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + ToasterConsumerModule oldModule, java.lang.AutoCloseable oldInstance) { + + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + protected void customValidation(){ + // No need to validate dependencies, since all dependencies have mandatory true flag in yang + // config-subsystem will perform the validation + } + + @Override + public java.lang.AutoCloseable createInstance() { + ToasterService toasterService = getRpcRegistryDependency().getRpcService(ToasterService.class); + + final ToastConsumerImpl consumer = new ToastConsumerImpl(toasterService); + final Registration> notificationRegistration = getNotificationServiceDependency() + .registerNotificationListener(ToastDone.class, consumer); + + final ToasterConsumerRuntimeRegistration runtimeRegistration = getRootRuntimeBeanRegistratorWrapper().register(consumer); + + final class AutoCloseableToastConsumer implements AutoCloseable, ToastConsumer { + + @Override + public void close() throws Exception { + runtimeRegistration.close(); + notificationRegistration.close(); + } + + @Override + public boolean createToast(Class type, int doneness) { + return consumer.createToast(type, doneness); + } + } + + return new AutoCloseableToastConsumer(); + } +} diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModuleFactory.java b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModuleFactory.java new file mode 100644 index 0000000000..f8048947b9 --- /dev/null +++ b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModuleFactory.java @@ -0,0 +1,19 @@ +/** +* Generated file + +* Generated from: yang module name: toaster-consumer-impl yang module local name: toaster-consumer-impl +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Feb 05 11:31:30 CET 2014 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.config.toaster_consumer.impl; + +/** +* +*/ +public class ToasterConsumerModuleFactory extends org.opendaylight.controller.config.yang.config.toaster_consumer.impl.AbstractToasterConsumerModuleFactory +{ + + +} diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java index 87e5787ef5..5a4b45c71e 100644 --- a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java +++ b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java @@ -7,33 +7,27 @@ */ package org.opendaylight.controller.sample.toaster.provider.impl; -import java.util.Hashtable; import java.util.concurrent.ExecutionException; -import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareConsumer; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; -import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; +import org.opendaylight.controller.config.yang.config.toaster_consumer.impl.ToasterConsumerRuntimeMXBean; import org.opendaylight.controller.sal.binding.api.NotificationListener; -import org.opendaylight.controller.sal.binding.api.NotificationService; import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer; -import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInputBuilder; -import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone; -import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType; -import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.*; import org.opendaylight.yangtools.yang.common.RpcResult; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ToastConsumerImpl extends AbstractBindingAwareConsumer implements BundleActivator, BindingAwareConsumer, ToastConsumer, - NotificationListener { +public class ToastConsumerImpl implements + ToastConsumer, + NotificationListener,ToasterConsumerRuntimeMXBean { private static final Logger log = LoggerFactory.getLogger(ToastConsumerImpl.class); private ToasterService toaster; - private ConsumerContext session; + public ToastConsumerImpl(ToasterService toaster) { + this.toaster = toaster; + } @Override public boolean createToast(Class type, int doneness) { @@ -42,45 +36,28 @@ public class ToastConsumerImpl extends AbstractBindingAwareConsumer implements B toastInput.setToasterToastType(type); try { - RpcResult result = getToastService().makeToast(toastInput.build()).get(); + RpcResult result = toaster.makeToast(toastInput.build()).get(); if (result.isSuccessful()) { - log.trace("Toast was successfuly finished"); + log.trace("Toast was successfully finished"); } else { - log.warn("Toast was not successfuly finished"); + log.warn("Toast was not successfully finished"); } return result.isSuccessful(); } catch (InterruptedException | ExecutionException e) { - log.warn("Error occured during toast creation"); + log.warn("Error occurred during toast creation"); } return false; } - @Override - @Deprecated - protected void startImpl(BundleContext context) { - context.registerService(ToastConsumer.class, this, new Hashtable()); - } - - @Override - public void onSessionInitialized(ConsumerContext session) { - this.session = session; - NotificationService notificationService = session.getSALService(NotificationService.class); - notificationService.registerNotificationListener(ToastDone.class, this); - } - @Override public void onNotification(ToastDone notification) { log.trace("ToastDone Notification Received: {} ",notification.getToastStatus()); - } - private ToasterService getToastService() { - if (toaster == null) { - toaster = session.getRpcService(ToasterService.class); - } - return toaster; + @Override + public Boolean makeHashBrownToast(Integer doneness) { + return createToast(HashBrown.class, doneness); } - } diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer-impl.yang b/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer-impl.yang new file mode 100644 index 0000000000..8bc1a5cc22 --- /dev/null +++ b/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer-impl.yang @@ -0,0 +1,81 @@ +// vi: set smarttab et sw=4 tabstop=4: +module toaster-consumer-impl { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl"; + prefix "toaster-consumer-impl"; + + import config { prefix config; revision-date 2013-04-05; } + import rpc-context { prefix rpcx; revision-date 2013-06-17; } + + import toaster-consumer { prefix toaster-consumer; revision-date 2014-01-31; } + import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; } + + description + "This module contains the base YANG definitions for + toaster-consumer impl implementation."; + + revision "2014-01-31" { + description + "Initial revision."; + } + + // This is the definition of a service implementation + identity toaster-consumer-impl { + base config:module-type; + config:provided-service toaster-consumer:toaster-consumer; + config:java-name-prefix ToasterConsumer; + } + + augment "/config:modules/config:module/config:configuration" { + case toaster-consumer-impl { + when "/config:modules/config:module/config:type = 'toaster-consumer-impl'"; + + container rpc-registry { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity mdsal:binding-rpc-registry; + } + } + } + + container notification-service { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity mdsal:binding-notification-service; + } + } + } + + } + } + + augment "/config:modules/config:module/config:state" { + case toaster-consumer-impl { + when "/config:modules/config:module/config:type = 'toaster-consumer-impl'"; + rpcx:rpc-context-instance "make-hash-brown-toast-rpc"; + } + } + + identity make-hash-brown-toast-rpc; + + rpc make-hash-brown-toast { + input { + uses rpcx:rpc-context-ref { + refine context-instance { + rpcx:rpc-context-instance make-hash-brown-toast-rpc; + } + } + leaf doneness { + type uint16; + } + } + output { + leaf result { + type boolean; + } + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer.yang b/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer.yang new file mode 100644 index 0000000000..c050ee86c6 --- /dev/null +++ b/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer.yang @@ -0,0 +1,26 @@ +// vi: set smarttab et sw=4 tabstop=4: +module toaster-consumer { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer"; + prefix "toaster-consumer"; + + import config { prefix config; revision-date 2013-04-05; } + + description + "This module contains the base YANG definitions for + toaster-consumer services."; + + revision "2014-01-31" { + description + "Initial revision."; + } + + // This is the definition of a service + identity toaster-consumer { + + base "config:service-type"; + + config:java-class "org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer"; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/samples/toaster-it/pom.xml b/opendaylight/md-sal/samples/toaster-it/pom.xml index a1925a53b5..d61393c225 100644 --- a/opendaylight/md-sal/samples/toaster-it/pom.xml +++ b/opendaylight/md-sal/samples/toaster-it/pom.xml @@ -4,7 +4,7 @@ sal-samples org.opendaylight.controller.samples - 1.0-SNAPSHOT + 1.1-SNAPSHOT sample-toaster-it @@ -13,10 +13,6 @@ https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL - - 3.0.0 - 1.5.0 - @@ -33,106 +29,39 @@ - - org.jacoco - jacoco-maven-plugin - - org.opendaylight.controller.* - - - - pre-test - - prepare-agent - - - - post-test - test - - report - - - - - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - - org.ops4j.pax.exam - - - maven-paxexam-plugin - - - [1.2.4,) - - - - generate-depends-file - - - - - - - - - - - - - - org.opendaylight.yangtools.thirdparty - xtend-lib-osgi - 2.4.3 - - - org.opendaylight.controller.samples - sample-toaster - 1.0-SNAPSHOT + org.opendaylight.controller + sal-binding-it + 1.1-SNAPSHOT org.opendaylight.controller.samples sample-toaster-consumer - 1.0-SNAPSHOT + 1.1-SNAPSHOT org.opendaylight.controller.samples sample-toaster-provider - 1.0-SNAPSHOT + 1.1-SNAPSHOT - org.opendaylight.controller - sal-binding-broker-impl - 1.0-SNAPSHOT + org.opendaylight.controller.samples + sample-toaster + 1.1-SNAPSHOT + - org.ops4j.pax.exam - pax-exam-container-native - ${exam.version} - test + junit + junit org.ops4j.pax.exam pax-exam-junit4 ${exam.version} - test org.ops4j.pax.exam @@ -140,11 +69,11 @@ ${exam.version} test - - org.opendaylight.controller - config-manager - 0.2.3-SNAPSHOT + org.ops4j.pax.exam + pax-exam-container-native + ${exam.version} + test equinoxSDK381 @@ -152,25 +81,5 @@ 3.8.1.v20120830-144521 test - - org.slf4j - log4j-over-slf4j - 1.7.2 - - - ch.qos.logback - logback-core - 1.0.9 - - - ch.qos.logback - logback-classic - 1.0.9 - - - org.opendaylight.yangtools.thirdparty - antlr4-runtime-osgi-nohead - 4.0 - diff --git a/opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java b/opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java index a7e1e9b445..38a4dd4661 100644 --- a/opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java +++ b/opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java @@ -7,116 +7,98 @@ */ package org.opendaylight.controller.sample.toaster.it; +import static org.junit.Assert.assertEquals; +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.*; +import static org.ops4j.pax.exam.CoreOptions.*; + +import javax.inject.Inject; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.config.yang.config.toaster_consumer.impl.ToasterConsumerRuntimeMXBean; +import org.opendaylight.controller.config.yang.config.toaster_provider.impl.ToasterProviderRuntimeMXBean; import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.HashBrown; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.WhiteBread; import org.ops4j.pax.exam.Configuration; import org.ops4j.pax.exam.Option; import org.ops4j.pax.exam.junit.PaxExam; -import org.osgi.framework.BundleContext; - -import javax.inject.Inject; - -import static org.junit.Assert.assertTrue; -import static org.ops4j.pax.exam.CoreOptions.junitBundles; -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 org.ops4j.pax.exam.options.DefaultCompositeOption; +import org.ops4j.pax.exam.util.Filter; import org.ops4j.pax.exam.util.PathUtils; +import java.lang.management.ManagementFactory; + @RunWith(PaxExam.class) public class ToasterTest { - public static final String ODL = "org.opendaylight.controller"; - public static final String YANG = "org.opendaylight.yangtools"; - public static final String CONTROLLER = "org.opendaylight.controller"; - public static final String YANGTOOLS = "org.opendaylight.yangtools"; - - - public static final String SAMPLE = "org.opendaylight.controller.samples"; + @Inject + @Filter(timeout=60*1000) + ToastConsumer toastConsumer; - @Test - public void properInitialized() throws Exception { + @Configuration + public Option[] config() { + return options(systemProperty("osgi.console").value("2401"), mavenBundle("org.slf4j", "slf4j-api") + .versionAsInProject(), // + mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), // + + systemProperty("logback.configurationFile").value( + "file:" + PathUtils.getBaseDir() + + "/src/test/resources/logback.xml"), + mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), // + mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), // + systemProperty("osgi.bundles.defaultStartLevel").value("4"), - Thread.sleep(500); // Waiting for services to get wired. + toasterBundles(), + mdSalCoreBundles(), - assertTrue(consumer.createToast(WhiteBread.class, 5)); + bindingAwareSalBundles(), + configMinumumBundles(), + // BASE Models + baseModelBundles(), + flowCapableModelBundles(), + // Set fail if unresolved bundle present + systemProperty("pax.exam.osgi.unresolved.fail").value("true"), + junitAndMockitoBundles()); } - @Inject - BindingAwareBroker broker; + private Option toasterBundles() { + return new DefaultCompositeOption( + mavenBundle("org.opendaylight.controller.samples", "sample-toaster-provider").versionAsInProject(), + mavenBundle("org.opendaylight.controller.samples", "sample-toaster-consumer").versionAsInProject(), + mavenBundle("org.opendaylight.controller.samples", "sample-toaster").versionAsInProject() + ); + } - @Inject - ToastConsumer consumer; + @Test + public void testToaster() throws Exception { - @Inject - BundleContext ctx; + MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); + ObjectName consumerOn = new ObjectName("org.opendaylight.controller:instanceName=toaster-consumer-impl,type=RuntimeBean,moduleFactoryName=toaster-consumer-impl"); + ObjectName providerOn = new ObjectName("org.opendaylight.controller:instanceName=toaster-provider-impl,type=RuntimeBean,moduleFactoryName=toaster-provider-impl"); - @Configuration - public Option[] config() { - return options(systemProperty("osgi.console").value("2401"), - systemProperty("logback.configurationFile").value( - "file:" + PathUtils.getBaseDir() - + "/src/test/resources/logback.xml"), - 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(), // - - mavenBundle(ODL, "sal-common").versionAsInProject(), // - mavenBundle(ODL, "sal-common-api").versionAsInProject(),// - mavenBundle(ODL, "sal-common-impl").versionAsInProject(), // - mavenBundle(ODL, "sal-common-util").versionAsInProject(), // - - mavenBundle(ODL, "config-api").versionAsInProject(), // - mavenBundle(ODL, "config-manager").versionAsInProject(), // - mavenBundle("commons-io", "commons-io").versionAsInProject(), - mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(), - - mavenBundle(CONTROLLER, "sal-binding-api").versionAsInProject(), // - mavenBundle(CONTROLLER, "sal-binding-config").versionAsInProject(), - mavenBundle(CONTROLLER, "sal-binding-broker-impl").versionAsInProject(), // - mavenBundle("org.javassist", "javassist").versionAsInProject(), // - mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject(), // - - mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), // - mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), // - mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), // - mavenBundle(YANGTOOLS, "yang-model-util").versionAsInProject(), // - mavenBundle(YANGTOOLS, "yang-parser-api").versionAsInProject(), - mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(), - - - mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(), // - mavenBundle(YANGTOOLS, "binding-model-api").versionAsInProject(), // - mavenBundle(YANGTOOLS, "binding-generator-util").versionAsInProject(), - mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(), - mavenBundle(YANGTOOLS, "binding-type-provider").versionAsInProject(), - mavenBundle(YANGTOOLS, "binding-generator-api").versionAsInProject(), - mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(), - mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(), - - - mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), // - mavenBundle(CONTROLLER, "sal-broker-impl").versionAsInProject(), // - mavenBundle(CONTROLLER, "sal-core-spi").versionAsInProject().update(), // - - mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), // - - mavenBundle(SAMPLE, "sample-toaster").versionAsInProject(), // - mavenBundle(SAMPLE, "sample-toaster-consumer").versionAsInProject(), // - mavenBundle(SAMPLE, "sample-toaster-provider").versionAsInProject(), // - mavenBundle(YANG, "concepts").versionAsInProject(), - mavenBundle(YANG, "yang-binding").versionAsInProject(), // - mavenBundle(YANG, "yang-common").versionAsInProject(), // - mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(), - mavenBundle("com.google.guava", "guava").versionAsInProject(), // - mavenBundle("org.javassist", "javassist").versionAsInProject(), - junitBundles() - ); + long toastsMade = (long) platformMBeanServer.getAttribute(providerOn, "ToastsMade"); + assertEquals(0, toastsMade); + + boolean toasts = true; + + // Make toasts using OSGi service + toasts &= toastConsumer.createToast(HashBrown.class, 4); + toasts &= toastConsumer.createToast(WhiteBread.class, 8); + + // Make toast using JMX/config-subsystem + toasts &= (Boolean)platformMBeanServer.invoke(consumerOn, "makeHashBrownToast", new Object[]{4}, new String[]{Integer.class.getName()}); + + Assert.assertTrue("Not all toasts done by " + toastConsumer, toasts); + + // Verify toasts made count on provider via JMX/config-subsystem + toastsMade = (long) platformMBeanServer.getAttribute(providerOn, "ToastsMade"); + assertEquals(3, toastsMade); } } diff --git a/opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml b/opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml new file mode 100644 index 0000000000..7a282db025 --- /dev/null +++ b/opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml @@ -0,0 +1,250 @@ + + + + + + urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27 + + 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?module=opendaylight-md-sal-dom&revision=2013-10-28 + + urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05 + + urn:ietf:params:netconf:capability:candidate:1.0 + urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04 + urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17 + + + urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28 + + urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24 + + urn:ietf:params:netconf:capability:rollback-on-error:1.0 + urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24 + + + 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:logback:config?module=config-logging&revision=2013-07-16 + urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09 + + + urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28 + + http://netconfcentral.org/ns/toaster?module=toaster&revision=2009-11-20 + urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer?module=toaster-consumer&revision=2014-01-31 + urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl?module=toaster-consumer-impl&revision=2014-01-31 + urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider?module=toaster-provider&revision=2014-01-31 + urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&revision=2014-01-31 + + + + + + + + + prefix:toaster-provider-impl + + toaster-provider-impl + + + binding:binding-rpc-registry + binding-rpc-broker + + + + + binding:binding-notification-service + + ref_binding-notification-broker + + + + + + prefix:toaster-consumer-impl + + toaster-consumer-impl + + + binding:binding-rpc-registry + binding-rpc-broker + + + + + binding:binding-notification-service + + ref_binding-notification-broker + + + + + + prefix:schema-service-singleton + + yang-schema-service + + + + prefix:hash-map-data-store + + hash-map-data-store + + + + prefix:dom-broker-impl + + dom-broker + + + dom:dom-data-store + + ref_hash-map-data-store + + + + + prefix:binding-broker-impl + + binding-broker-impl + + + binding:binding-notification-service + + ref_binding-notification-broker + + + + binding: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 + + + dom:dom-broker-osgi-registry + + ref_dom-broker + + + + binding:binding-dom-mapping-service + + ref_runtime-mapping-singleton + + + + + + + + dom:schema-service + + + ref_yang-schema-service + + /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service'] + + + + + + binding:binding-notification-service + + + ref_binding-notification-broker + + /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker'] + + + + + + dom:dom-data-store + + + ref_hash-map-data-store + + /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store'] + + + + + binding:binding-rpc-registry + + binding-rpc-broker + /modules/module[type='binding-broker-impl'][name='binding-broker-impl'] + + + + + binding:binding-broker-osgi-registry + + + ref_binding-broker-impl + + /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl'] + + + + + + binding-impl:binding-dom-mapping-service + + + ref_runtime-mapping-singleton + + /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton'] + + + + + + dom:dom-broker-osgi-registry + + + ref_dom-broker + /config/modules/module[name='dom-broker-impl']/instance[name='dom-broker'] + + + + + + binding:binding-data-broker + + + ref_binding-data-broker + + /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker'] + + + + + + + + + + + diff --git a/opendaylight/md-sal/samples/toaster-it/src/test/resources/logback.xml b/opendaylight/md-sal/samples/toaster-it/src/test/resources/logback.xml index 2d63ce5744..f904f9726e 100644 --- a/opendaylight/md-sal/samples/toaster-it/src/test/resources/logback.xml +++ b/opendaylight/md-sal/samples/toaster-it/src/test/resources/logback.xml @@ -7,7 +7,10 @@ - + + + + diff --git a/opendaylight/md-sal/samples/toaster-provider/pom.xml b/opendaylight/md-sal/samples/toaster-provider/pom.xml index ca1e3b4689..1a540fe949 100644 --- a/opendaylight/md-sal/samples/toaster-provider/pom.xml +++ b/opendaylight/md-sal/samples/toaster-provider/pom.xml @@ -15,6 +15,11 @@ + + ${project.build.directory}/generated-sources/config + 1.1-SNAPSHOT + + @@ -22,10 +27,67 @@ maven-bundle-plugin - org.opendaylight.controller.sample.toaster.provider.ToasterProvider + + org.opendaylight.controller.config.yang.toaster_provider, + + * + + org.opendaylight.yangtools + yang-maven-plugin + + + config + + generate-sources + + + + + + org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + + ${jmxGeneratorPath} + + + urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang + + + + + true + + + + + + org.opendaylight.controller + yang-jmx-generator-plugin + ${config.version} + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${jmxGeneratorPath} + + + + + @@ -43,5 +105,13 @@ org.opendaylight.controller sal-common-util + + org.opendaylight.controller + sal-binding-config + + + org.opendaylight.controller + config-api + diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java new file mode 100644 index 0000000000..1029105233 --- /dev/null +++ b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java @@ -0,0 +1,72 @@ +/** +* Generated file + +* Generated from: yang module name: toaster-provider-impl yang module local name: toaster-provider-impl +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Feb 05 11:05:32 CET 2014 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.config.toaster_provider.impl; + +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sample.toaster.provider.OpendaylightToaster; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData; +import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService; + +/** +* +*/ +public final class ToasterProviderModule extends org.opendaylight.controller.config.yang.config.toaster_provider.impl.AbstractToasterProviderModule + { + + public ToasterProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public ToasterProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + ToasterProviderModule oldModule, java.lang.AutoCloseable oldInstance) { + + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + protected void customValidation() { + // No need to validate dependencies, since all dependencies have mandatory true flag in yang + // config-subsystem will perform the validation for dependencies + } + + @Override + public java.lang.AutoCloseable createInstance() { + final OpendaylightToaster opendaylightToaster = new OpendaylightToaster(); + + // Register to md-sal + opendaylightToaster.setNotificationProvider(getNotificationServiceDependency()); + final BindingAwareBroker.RpcRegistration rpcRegistration = getRpcRegistryDependency() + .addRpcImplementation(ToasterService.class, opendaylightToaster); + + // Register runtimeBean for toaster statistics via JMX + final ToasterProviderRuntimeRegistration runtimeReg = getRootRuntimeBeanRegistratorWrapper().register( + opendaylightToaster); + + // Wrap toaster as AutoCloseable and close registrations to md-sal at + // close() + final class AutoCloseableToaster implements AutoCloseable, ToasterData { + + @Override + public void close() throws Exception { + rpcRegistration.close(); + runtimeReg.close(); + } + + @Override + public Toaster getToaster() { + return opendaylightToaster.getToaster(); + } + } + + return new AutoCloseableToaster(); + } + +} diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModuleFactory.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModuleFactory.java new file mode 100644 index 0000000000..53a5071746 --- /dev/null +++ b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModuleFactory.java @@ -0,0 +1,19 @@ +/** +* Generated file + +* Generated from: yang module name: toaster-provider-impl yang module local name: toaster-provider-impl +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Feb 05 11:05:32 CET 2014 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.config.toaster_provider.impl; + +/** +* +*/ +public class ToasterProviderModuleFactory extends org.opendaylight.controller.config.yang.config.toaster_provider.impl.AbstractToasterProviderModuleFactory +{ + + +} diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java index c3b9716783..a484154edf 100644 --- a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java +++ b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java @@ -13,7 +13,9 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; +import org.opendaylight.controller.config.yang.config.toaster_provider.impl.ToasterProviderRuntimeMXBean; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.controller.sal.common.util.Futures; import org.opendaylight.controller.sal.common.util.Rpcs; @@ -31,7 +33,7 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class OpendaylightToaster implements ToasterData, ToasterService { +public class OpendaylightToaster implements ToasterData, ToasterService, ToasterProviderRuntimeMXBean { private static final Logger log = LoggerFactory.getLogger(OpendaylightToaster.class); @@ -102,6 +104,13 @@ public class OpendaylightToaster implements ToasterData, ToasterService { log.trace("Toast: {} doneness: {}", toastType, toastDoneness); } + private final AtomicLong toastsMade = new AtomicLong(0); + + @Override + public Long getToastsMade() { + return toastsMade.get(); + } + private class MakeToastTask implements Callable> { final MakeToastInput toastRequest; @@ -120,6 +129,9 @@ public class OpendaylightToaster implements ToasterData, ToasterService { log.trace("Toast Done"); logToastInput(toastRequest); currentTask = null; + + toastsMade.incrementAndGet(); + return Rpcs. getRpcResult(true, null, Collections. emptySet()); } } diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java deleted file mode 100644 index ae482ed978..0000000000 --- a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java +++ /dev/null @@ -1,49 +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.sample.toaster.provider; - -import java.util.Collection; -import java.util.Collections; - -import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; -import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService; -import org.opendaylight.yangtools.yang.binding.RpcService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ToasterProvider extends AbstractBindingAwareProvider { - private static final Logger log = LoggerFactory.getLogger(ToasterProvider.class); - - private ProviderContext providerContext; - private final OpendaylightToaster toaster; - - public ToasterProvider() { - toaster = new OpendaylightToaster(); - } - - @Override - public void onSessionInitiated(ProviderContext session) { - log.info("Provider Session initialized"); - - this.providerContext = session; - toaster.setNotificationProvider(session.getSALService(NotificationProviderService.class)); - providerContext.addRpcImplementation(ToasterService.class, toaster); - } - - @Override - public Collection getImplementations() { - return Collections.emptySet(); - } - - @Override - public Collection getFunctionality() { - return Collections.emptySet(); - } -} diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang b/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang new file mode 100644 index 0000000000..0be8874245 --- /dev/null +++ b/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang @@ -0,0 +1,63 @@ +// vi: set smarttab et sw=4 tabstop=4: +module toaster-provider-impl { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl"; + prefix "toaster-provider-impl"; + + import config { prefix config; revision-date 2013-04-05; } + import toaster-provider { prefix toaster-provider; revision-date 2014-01-31; } + import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; } + + description + "This module contains the base YANG definitions for + toaster-provider impl implementation."; + + revision "2014-01-31" { + description + "Initial revision."; + } + + // This is the definition of a service implementation + identity toaster-provider-impl { + base config:module-type; + config:provided-service toaster-provider:toaster-provider; + config:java-name-prefix ToasterProvider; + } + + augment "/config:modules/config:module/config:configuration" { + case toaster-provider-impl { + when "/config:modules/config:module/config:type = 'toaster-provider-impl'"; + + container rpc-registry { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity mdsal:binding-rpc-registry; + } + } + } + + container notification-service { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity mdsal:binding-notification-service; + } + } + } + + } + } + + augment "/config:modules/config:module/config:state" { + case toaster-provider-impl { + when "/config:modules/config:module/config:type = 'toaster-provider-impl'"; + + leaf toasts-made { + type uint32; + } + + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider.yang b/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider.yang new file mode 100644 index 0000000000..a5fba07d74 --- /dev/null +++ b/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider.yang @@ -0,0 +1,26 @@ +// vi: set smarttab et sw=4 tabstop=4: +module toaster-provider { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider"; + prefix "toaster-provider"; + + import config { prefix config; revision-date 2013-04-05; } + + description + "This module contains the base YANG definitions for + toaster-provider services."; + + revision "2014-01-31" { + description + "Initial revision."; + } + + // This is the definition of a service + identity toaster-provider { + + base "config:service-type"; + + config:java-class "org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData"; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/samples/toaster/pom.xml b/opendaylight/md-sal/samples/toaster/pom.xml index 599fd714b8..ad6d814c1b 100644 --- a/opendaylight/md-sal/samples/toaster/pom.xml +++ b/opendaylight/md-sal/samples/toaster/pom.xml @@ -19,7 +19,6 @@ org.opendaylight.yangtools yang-maven-plugin - ${yangtools.version} diff --git a/opendaylight/netconf/config-netconf-connector/pom.xml b/opendaylight/netconf/config-netconf-connector/pom.xml index 6db7f3a56d..f8993a09e7 100644 --- a/opendaylight/netconf/config-netconf-connector/pom.xml +++ b/opendaylight/netconf/config-netconf-connector/pom.xml @@ -4,7 +4,7 @@ netconf-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT config-netconf-connector ${project.artifactId} 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 592d8e4f3b..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 @@ -8,9 +8,8 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations; -import java.util.HashMap; -import java.util.Map; - +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.jmx.CommitStatus; import org.opendaylight.controller.config.util.ConfigRegistryClient; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; @@ -25,6 +24,9 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; +import java.util.HashMap; +import java.util.Map; + public class Commit extends AbstractConfigNetconfOperation { private static final Logger logger = LoggerFactory.getLogger(Commit.class); @@ -55,16 +57,19 @@ public class Commit extends AbstractConfigNetconfOperation { try { status = this.transactionProvider.commitTransaction(); } catch (final IllegalStateException e) { + // 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(), "Operation failed. Use 'get-config' or 'edit-config' before triggering 'commit' operation"); throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error, errorInfo); - } catch (final NetconfDocumentedException e) { - throw new NetconfDocumentedException( - "Unable to retrieve config snapshot after commit for persister, details: " + e.getMessage(), - ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error, e.getErrorInfo()); + } catch (ValidationException e) { + throw NetconfDocumentedException.wrap(e); + } catch (ConflictingVersionException e) { + throw NetconfDocumentedException.wrap(e); + } logger.trace("Datastore {} committed successfully: {}", Datastore.candidate, status); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/DiscardChanges.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/DiscardChanges.java index 3da02a8430..8965deb630 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/DiscardChanges.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/DiscardChanges.java @@ -8,9 +8,6 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations; -import java.util.HashMap; -import java.util.Map; - import org.opendaylight.controller.config.util.ConfigRegistryClient; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity; @@ -24,6 +21,9 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; +import java.util.HashMap; +import java.util.Map; + public class DiscardChanges extends AbstractConfigNetconfOperation { public static final String DISCARD = "discard-changes"; @@ -53,6 +53,7 @@ public class DiscardChanges extends AbstractConfigNetconfOperation { try { fromXml(xml); } catch (final IllegalArgumentException e) { + //FIXME where can IllegalStateException be thrown? logger.warn("Rpc error: {}", ErrorTag.bad_attribute, e); final Map errorInfo = new HashMap<>(); errorInfo.put(ErrorTag.bad_attribute.name(), e.getMessage()); @@ -63,6 +64,7 @@ public class DiscardChanges extends AbstractConfigNetconfOperation { try { this.transactionProvider.abortTransaction(); } catch (final IllegalStateException e) { + //FIXME where can IllegalStateException be thrown? logger.warn("Abort failed: ", e); final Map errorInfo = new HashMap<>(); errorInfo diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Validate.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Validate.java index 24611c26cd..017b5e6c39 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Validate.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Validate.java @@ -66,12 +66,14 @@ public class Validate extends AbstractConfigNetconfOperation { try { checkXml(xml); } catch (IllegalStateException e) { + //FIXME where can IllegalStateException be thrown? I see precondition that guards for programming bugs.. logger.warn("Rpc error: {}", ErrorTag.missing_attribute, e); final Map errorInfo = new HashMap<>(); errorInfo.put(ErrorTag.missing_attribute.name(), "Missing value of datastore attribute"); throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.rpc, ErrorTag.missing_attribute, ErrorSeverity.error, errorInfo); } catch (final IllegalArgumentException e) { + // FIXME use checked exception if it has domain meaning logger.warn("Rpc error: {}", ErrorTag.bad_attribute, e); final Map errorInfo = new HashMap<>(); errorInfo.put(ErrorTag.bad_attribute.name(), e.getMessage()); @@ -83,10 +85,7 @@ public class Validate extends AbstractConfigNetconfOperation { transactionProvider.validateTransaction(); } catch (ValidationException e) { logger.warn("Validation failed", e); - final Map errorInfo = new HashMap<>(); - errorInfo.put(ErrorTag.operation_failed.name(), "Validation failed"); - throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed, - ErrorSeverity.error, errorInfo); + throw NetconfDocumentedException.wrap(e); } catch (IllegalStateException e) { logger.warn("Validation failed", e); final Map errorInfo = new HashMap<>(); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java index 97535ba1e2..bd85f948f5 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java @@ -12,7 +12,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; -import org.opendaylight.controller.config.api.JmxAttributeValidationException; import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.util.ConfigRegistryClient; import org.opendaylight.controller.config.util.ConfigTransactionClient; @@ -87,7 +86,11 @@ public class EditConfig extends AbstractConfigNetconfOperation { EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException { try { set(configRegistryClient, editConfigExecution); - } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) { + + } catch (IllegalStateException e) { + //FIXME: when can IllegalStateException be thrown? + // JmxAttributeValidationException is wrapped in DynamicWritableWrapper with ValidationException + // ValidationException is not thrown until validate or commit is issued logger.warn("Set phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e); final Map errorInfo = new HashMap<>(); errorInfo.put(ErrorTag.operation_failed.name(), e.getMessage()); @@ -101,7 +104,8 @@ public class EditConfig extends AbstractConfigNetconfOperation { EditConfigExecution editConfigExecution) throws NetconfDocumentedException { try { test(configRegistryClient, editConfigExecution, editConfigExecution.getDefaultStrategy()); - } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) { + } catch (IllegalStateException | ValidationException e) { + //FIXME: when can IllegalStateException be thrown? logger.warn("Test phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e); final Map errorInfo = new HashMap<>(); errorInfo.put(ErrorTag.operation_failed.name(), e.getMessage()); @@ -112,7 +116,7 @@ public class EditConfig extends AbstractConfigNetconfOperation { } private void test(ConfigRegistryClient configRegistryClient, EditConfigExecution execution, - EditStrategyType editStrategyType) { + EditStrategyType editStrategyType) throws ValidationException { ObjectName taON = transactionProvider.getTestTransaction(); try { @@ -237,6 +241,7 @@ public class EditConfig extends AbstractConfigNetconfOperation { return identityNameToSchemaNode.containsKey(idName); } + // FIXME method never used public IdentitySchemaNode getIdentitySchemaNode(String idName) { Preconditions.checkState(identityNameToSchemaNode.containsKey(idName), "No identity under name %s", idName); return identityNameToSchemaNode.get(idName); 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-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java index cd3b44852c..d7cbf6680d 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java @@ -10,11 +10,11 @@ package org.opendaylight.controller.netconf.confignetconfconnector.transactions; import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import org.opendaylight.controller.config.api.ConflictingVersionException; import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.jmx.CommitStatus; import org.opendaylight.controller.config.util.ConfigRegistryClient; import org.opendaylight.controller.config.util.ConfigTransactionClient; -import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -94,7 +94,7 @@ public class TransactionProvider implements AutoCloseable { /** * Commit and notification send must be atomic */ - public synchronized CommitStatus commitTransaction() throws NetconfDocumentedException { + public synchronized CommitStatus commitTransaction() throws ValidationException, ConflictingVersionException { final Optional maybeTaON = getTransaction(); Preconditions.checkState(maybeTaON.isPresent(), "No transaction found for session " + netconfSessionIdForReporting); ObjectName taON = maybeTaON.get(); @@ -108,7 +108,7 @@ public class TransactionProvider implements AutoCloseable { // no clean up: user can reconfigure and recover this transaction logger.warn("Transaction {} failed on {}", taON, validationException.toString()); throw validationException; - } catch (Exception e) { + } catch (ConflictingVersionException e) { logger.error("Exception while commit of {}, aborting transaction", taON, e); // clean up abortTransaction(); @@ -142,7 +142,7 @@ public class TransactionProvider implements AutoCloseable { transactionClient.validateConfig(); } - public void validateTestTransaction(ObjectName taON) { + public void validateTestTransaction(ObjectName taON) throws ValidationException { ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON); transactionClient.validateConfig(); } diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java index 72d62efe84..0a4f82f057 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java @@ -8,33 +8,11 @@ package org.opendaylight.controller.netconf.confignetconfconnector; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.ObjectName; -import javax.xml.parsers.ParserConfigurationException; - +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.apache.commons.lang3.StringUtils; import org.junit.Before; import org.junit.Ignore; @@ -42,6 +20,8 @@ import org.junit.Test; import org.junit.matchers.JUnitMatchers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; @@ -92,11 +72,31 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import javax.xml.parsers.ParserConfigurationException; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; public class NetconfMappingTest extends AbstractConfigTest { @@ -130,7 +130,7 @@ public class NetconfMappingTest extends AbstractConfigTest { transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID); } - private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException { + private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException, ValidationException, ConflictingVersionException { final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction(); final ObjectName on = transaction.createModule(this.factory.getImplementationName(), instanceName); diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java index 505a91c6ce..b70a66f5ef 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java @@ -17,6 +17,7 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; +import org.opendaylight.controller.config.api.ValidationException; import org.opendaylight.controller.config.util.ConfigRegistryClient; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot; @@ -79,7 +80,7 @@ public class EditConfigTest { } @Test - public void test() throws NetconfDocumentedException { + public void test() throws NetconfDocumentedException, ValidationException { EditConfig edit = new EditConfig(yangStoreSnapshot, provider, configRegistry, ValidateTest.NETCONF_SESSION_ID_FOR_REPORTING); EditConfigStrategy editStrat = mock(EditConfigStrategy.class); diff --git a/opendaylight/netconf/config-persister-impl/pom.xml b/opendaylight/netconf/config-persister-impl/pom.xml index 590381038a..daaf60c1d3 100644 --- a/opendaylight/netconf/config-persister-impl/pom.xml +++ b/opendaylight/netconf/config-persister-impl/pom.xml @@ -4,7 +4,7 @@ netconf-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT config-persister-impl ${project.artifactId} @@ -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 460aec6ac6..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 @@ -8,20 +8,7 @@ package org.opendaylight.controller.netconf.persist.impl; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetSocketAddress; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import javax.annotation.concurrent.Immutable; - +import com.google.common.base.Preconditions; import org.opendaylight.controller.config.api.ConflictingVersionException; import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; import org.opendaylight.controller.netconf.api.NetconfMessage; @@ -38,35 +25,26 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; -import com.google.common.base.Preconditions; -import io.netty.channel.EventLoopGroup; +import javax.annotation.concurrent.Immutable; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; @Immutable public class ConfigPusher { private static final Logger logger = LoggerFactory.getLogger(ConfigPusher.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 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( @@ -97,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,8 +84,9 @@ public class ConfigPusher { EditAndCommitResponse editAndCommitResponse = pushLastConfig(configSnapshotHolder, netconfClient); return new EditAndCommitResponseWithRetries(editAndCommitResponse, retryAttempt); } 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 { @@ -129,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(); @@ -155,21 +135,29 @@ public class ConfigPusher { logger.trace("Session id received from netconf server: {}", netconfClient.getClientSession()); return netconfClient; } - logger.debug("Polling hello from netconf, attempt {}, capabilities {}", attempt, latestCapabilities); + Set allNotFound = computeNotFoundCapabilities(expectedCaps, latestCapabilities); + logger.debug("Netconf server did not provide required capabilities. Attempt {}. " + + "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 = new HashSet<>(expectedCaps); - allNotFound.removeAll(latestCapabilities); + Set allNotFound = computeNotFoundCapabilities(expectedCaps, latestCapabilities); logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}", allNotFound, expectedCaps, latestCapabilities); throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound); } + private static Set computeNotFoundCapabilities(Set expectedCaps, Set latestCapabilities) { + Set allNotFound = new HashSet<>(expectedCaps); + allNotFound.removeAll(latestCapabilities); + return allNotFound; + } + /** * Sends two RPCs to the netconf server: edit-config and commit. @@ -222,17 +210,23 @@ public class ConfigPusher { } - private static NetconfMessage sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfClient netconfClient) throws IOException { + 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 (RuntimeException | ExecutionException | InterruptedException | TimeoutException 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 logger.debug("Error while executing netconf transaction {} to {}", request, netconfClient, e); throw new IOException("Failed to execute netconf transaction", e); } } + // load editConfig.xml template, populate /rpc/edit-config/config with parameter private static NetconfMessage createEditConfigMessage(Element dataElement) { String editConfigResourcePath = "/netconfOp/editConfig.xml"; @@ -318,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/ietf-netconf-monitoring-extension/pom.xml b/opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml index c6111ab395..7b872db9a6 100644 --- a/opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml +++ b/opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml @@ -2,7 +2,7 @@ netconf-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT 4.0.0 ietf-netconf-monitoring-extension diff --git a/opendaylight/netconf/ietf-netconf-monitoring/pom.xml b/opendaylight/netconf/ietf-netconf-monitoring/pom.xml index e6a186c881..f1e5764ca6 100644 --- a/opendaylight/netconf/ietf-netconf-monitoring/pom.xml +++ b/opendaylight/netconf/ietf-netconf-monitoring/pom.xml @@ -3,7 +3,7 @@ netconf-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT 4.0.0 ietf-netconf-monitoring diff --git a/opendaylight/netconf/netconf-api/pom.xml b/opendaylight/netconf/netconf-api/pom.xml index 971f4a7bb4..3b5ed82518 100644 --- a/opendaylight/netconf/netconf-api/pom.xml +++ b/opendaylight/netconf/netconf-api/pom.xml @@ -4,7 +4,7 @@ netconf-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT 4.0.0 netconf-api @@ -50,6 +50,7 @@ javax.management, + org.opendaylight.controller.config.api, org.opendaylight.controller.config.api.jmx, org.opendaylight.protocol.framework, io.netty.channel, diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDocumentedException.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDocumentedException.java index 5a85e94257..ceeca51def 100644 --- a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDocumentedException.java +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDocumentedException.java @@ -8,7 +8,11 @@ package org.opendaylight.controller.netconf.api; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; + import java.util.Collections; +import java.util.HashMap; import java.util.Map; /** @@ -19,6 +23,8 @@ public class NetconfDocumentedException extends Exception { private static final long serialVersionUID = 1L; + + public enum ErrorType { transport, rpc, protocol, application; @@ -84,6 +90,20 @@ public class NetconfDocumentedException extends Exception { this.errorInfo = errorInfo; } + public static NetconfDocumentedException wrap(ValidationException e) throws NetconfDocumentedException { + final Map errorInfo = new HashMap<>(); + errorInfo.put(ErrorTag.operation_failed.name(), "Validation failed"); + throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed, + ErrorSeverity.error, errorInfo); + } + + public static NetconfDocumentedException wrap(ConflictingVersionException e) throws NetconfDocumentedException { + final Map errorInfo = new HashMap<>(); + errorInfo.put(ErrorTag.operation_failed.name(), "Optimistic lock failed"); + throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed, + ErrorSeverity.error, errorInfo); + } + public ErrorType getErrorType() { return this.errorType; } diff --git a/opendaylight/netconf/netconf-client/pom.xml b/opendaylight/netconf/netconf-client/pom.xml index e6cba9258e..b0f5f74810 100644 --- a/opendaylight/netconf/netconf-client/pom.xml +++ b/opendaylight/netconf/netconf-client/pom.xml @@ -4,7 +4,7 @@ netconf-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT netconf-client ${project.artifactId} diff --git a/opendaylight/netconf/netconf-impl/pom.xml b/opendaylight/netconf/netconf-impl/pom.xml index f4fc1ff0d5..85fff89777 100644 --- a/opendaylight/netconf/netconf-impl/pom.xml +++ b/opendaylight/netconf/netconf-impl/pom.xml @@ -4,7 +4,7 @@ netconf-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT 4.0.0 netconf-impl diff --git a/opendaylight/netconf/netconf-it/pom.xml b/opendaylight/netconf/netconf-it/pom.xml index 9b0c7ab08a..57067f47ec 100644 --- a/opendaylight/netconf/netconf-it/pom.xml +++ b/opendaylight/netconf/netconf-it/pom.xml @@ -5,7 +5,7 @@ netconf-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT netconf-it @@ -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-mapping-api/pom.xml b/opendaylight/netconf/netconf-mapping-api/pom.xml index d9aa0ab64d..18c27238e9 100644 --- a/opendaylight/netconf/netconf-mapping-api/pom.xml +++ b/opendaylight/netconf/netconf-mapping-api/pom.xml @@ -4,7 +4,7 @@ netconf-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT 4.0.0 netconf-mapping-api diff --git a/opendaylight/netconf/netconf-monitoring/pom.xml b/opendaylight/netconf/netconf-monitoring/pom.xml index d1fb6aabeb..568aca9063 100644 --- a/opendaylight/netconf/netconf-monitoring/pom.xml +++ b/opendaylight/netconf/netconf-monitoring/pom.xml @@ -3,7 +3,7 @@ netconf-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT 4.0.0 netconf-monitoring diff --git a/opendaylight/netconf/netconf-ssh/pom.xml b/opendaylight/netconf/netconf-ssh/pom.xml index efad2148e9..73e0a467c0 100644 --- a/opendaylight/netconf/netconf-ssh/pom.xml +++ b/opendaylight/netconf/netconf-ssh/pom.xml @@ -2,7 +2,7 @@ netconf-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT ../ 4.0.0 diff --git a/opendaylight/netconf/netconf-util/pom.xml b/opendaylight/netconf/netconf-util/pom.xml index e5bab5633b..5df329def0 100644 --- a/opendaylight/netconf/netconf-util/pom.xml +++ b/opendaylight/netconf/netconf-util/pom.xml @@ -4,7 +4,7 @@ netconf-subsystem org.opendaylight.controller - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT netconf-util ${project.artifactId} 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/netconf/pom.xml b/opendaylight/netconf/pom.xml index 2c2ef3b507..ae75657e5a 100644 --- a/opendaylight/netconf/pom.xml +++ b/opendaylight/netconf/pom.xml @@ -8,7 +8,7 @@ ../commons/opendaylight - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT netconf-subsystem pom ${project.artifactId} @@ -48,8 +48,6 @@ 2.4.0 1.7.2 4.0.10.Final - 0.2.4-SNAPSHOT - 0.2.4-SNAPSHOT ${project.build.directory}/generated-sources/sal diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java index 680b028f9a..f93191220b 100644 --- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java @@ -37,12 +37,15 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronPort; import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet; import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs; import org.opendaylight.controller.northbound.commons.RestMessages; +import org.opendaylight.controller.northbound.commons.exception.BadRequestException; +import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException; +import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException; import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException; import org.opendaylight.controller.sal.utils.ServiceHelper; /** - * Open DOVE Northbound REST APIs.
    - * This class provides REST APIs for managing the open DOVE + * Neutron Northbound REST APIs.
    + * This class provides REST APIs for managing Neutron Floating IPs * *
    *
    @@ -139,7 +142,7 @@ public class NeutronFloatingIPsNorthbound { + RestMessages.SERVICEUNAVAILABLE.toString()); } if (!floatingIPInterface.floatingIPExists(floatingipUUID)) - return Response.status(404).build(); + throw new ResourceNotFoundException("Floating IP UUID doesn't exist."); if (fields.size() > 0) { NeutronFloatingIP ans = floatingIPInterface.getFloatingIP(floatingipUUID); return Response.status(200).entity( @@ -187,42 +190,42 @@ public class NeutronFloatingIPsNorthbound { NeutronFloatingIP singleton = input.getSingleton(); // check existence of id in cache and return badrequest if exists if (floatingIPInterface.floatingIPExists(singleton.getID())) - return Response.status(400).build(); + throw new BadRequestException("Floating IP UUID already exists."); // check if the external network is specified, exists, and is an external network String externalNetworkUUID = singleton.getFloatingNetworkUUID(); if (externalNetworkUUID == null) - return Response.status(400).build(); + throw new BadRequestException("external network UUID doesn't exist."); if (!networkInterface.networkExists(externalNetworkUUID)) - return Response.status(400).build(); + throw new BadRequestException("external network UUID doesn't exist."); NeutronNetwork externNetwork = networkInterface.getNetwork(externalNetworkUUID); if (!externNetwork.isRouterExternal()) - return Response.status(400).build(); + throw new BadRequestException("external network isn't marked router:external"); // if floating IP is specified, make sure it can come from the network String floatingIP = singleton.getFloatingIPAddress(); if (floatingIP != null) { if (externNetwork.getSubnets().size() > 1) - return Response.status(400).build(); + throw new BadRequestException("external network doesn't have a subnet"); NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0)); if (!externSubnet.isValidIP(floatingIP)) - return Response.status(400).build(); + throw new BadRequestException("external IP isn't valid for the specified subnet."); if (externSubnet.isIPInUse(floatingIP)) - return Response.status(409).build(); + throw new ResourceConflictException("floating IP is in use."); } // if port_id is specified, then check that the port exists and has at least one IP String port_id = singleton.getPortUUID(); if (port_id != null) { String fixedIP = null; // used for the fixedIP calculation if (!portInterface.portExists(port_id)) - return Response.status(404).build(); + throw new ResourceNotFoundException("Port UUID doesn't exist."); NeutronPort port = portInterface.getPort(port_id); if (port.getFixedIPs().size() < 1) - return Response.status(400).build(); + throw new BadRequestException("port UUID doesn't have an IP address."); // if there is more than one fixed IP then check for fixed_ip_address // and that it is in the list of port addresses if (port.getFixedIPs().size() > 1) { fixedIP = singleton.getFixedIPAddress(); if (fixedIP == null) - return Response.status(400).build(); + throw new BadRequestException("fixed IP address doesn't exist."); Iterator i = port.getFixedIPs().iterator(); boolean validFixedIP = false; while (i.hasNext() && !validFixedIP) { @@ -231,15 +234,15 @@ public class NeutronFloatingIPsNorthbound { validFixedIP = true; } if (!validFixedIP) - return Response.status(400).build(); + throw new BadRequestException("can't find a valid fixed IP address"); } else { fixedIP = port.getFixedIPs().get(0).getIpAddress(); if (singleton.getFixedIPAddress() != null && !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress())) - return Response.status(400).build(); + throw new BadRequestException("mismatched fixed IP address in request"); } //lastly check that this fixed IP address isn't already used if (port.isBoundToFloatingIP(fixedIP)) - return Response.status(409).build(); + throw new ResourceConflictException("fixed IP is in use."); singleton.setFixedIPAddress(fixedIP); } Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null); @@ -259,7 +262,7 @@ public class NeutronFloatingIPsNorthbound { } } } else { - return Response.status(400).build(); + throw new BadRequestException("only singleton requests allowed."); } return Response.status(201).entity(input).build(); } @@ -303,14 +306,14 @@ public class NeutronFloatingIPsNorthbound { + RestMessages.SERVICEUNAVAILABLE.toString()); } if (!floatingIPInterface.floatingIPExists(floatingipUUID)) - return Response.status(404).build(); + throw new ResourceNotFoundException("Floating IP UUID doesn't exist."); NeutronFloatingIP sourceFloatingIP = floatingIPInterface.getFloatingIP(floatingipUUID); if (!input.isSingleton()) - return Response.status(400).build(); + throw new BadRequestException("only singleton requests allowed."); NeutronFloatingIP singleton = input.getSingleton(); if (singleton.getID() != null) - return Response.status(400).build(); + throw new BadRequestException("singleton UUID doesn't exist."); NeutronNetwork externNetwork = networkInterface.getNetwork( sourceFloatingIP.getFloatingNetworkUUID()); @@ -319,12 +322,12 @@ public class NeutronFloatingIPsNorthbound { String floatingIP = singleton.getFloatingIPAddress(); if (floatingIP != null) { if (externNetwork.getSubnets().size() > 1) - return Response.status(400).build(); + throw new BadRequestException("external network doesn't have a subnet."); NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0)); if (!externSubnet.isValidIP(floatingIP)) - return Response.status(400).build(); + throw new BadRequestException("floating IP not valid for external subnet"); if (externSubnet.isIPInUse(floatingIP)) - return Response.status(409).build(); + throw new ResourceConflictException("floating IP is in use."); } // if port_id is specified, then check that the port exists and has at least one IP @@ -332,16 +335,16 @@ public class NeutronFloatingIPsNorthbound { if (port_id != null) { String fixedIP = null; // used for the fixedIP calculation if (!portInterface.portExists(port_id)) - return Response.status(404).build(); + throw new ResourceNotFoundException("Port UUID doesn't exist."); NeutronPort port = portInterface.getPort(port_id); if (port.getFixedIPs().size() < 1) - return Response.status(400).build(); + throw new BadRequestException("port ID doesn't have a fixed IP address."); // if there is more than one fixed IP then check for fixed_ip_address // and that it is in the list of port addresses if (port.getFixedIPs().size() > 1) { fixedIP = singleton.getFixedIPAddress(); if (fixedIP == null) - return Response.status(400).build(); + throw new BadRequestException("request doesn't have a fixed IP address"); Iterator i = port.getFixedIPs().iterator(); boolean validFixedIP = false; while (i.hasNext() && !validFixedIP) { @@ -350,16 +353,16 @@ public class NeutronFloatingIPsNorthbound { validFixedIP = true; } if (!validFixedIP) - return Response.status(400).build(); + throw new BadRequestException("couldn't find a valid fixed IP address"); } else { fixedIP = port.getFixedIPs().get(0).getIpAddress(); if (singleton.getFixedIPAddress() != null && !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress())) - return Response.status(400).build(); + throw new BadRequestException("mismatch in fixed IP addresses"); } //lastly check that this fixed IP address isn't already used if (port.isBoundToFloatingIP(fixedIP)) - return Response.status(409).build(); + throw new ResourceConflictException("fixed IP is in use."); singleton.setFixedIPAddress(fixedIP); } NeutronFloatingIP target = floatingIPInterface.getFloatingIP(floatingipUUID); @@ -403,7 +406,7 @@ public class NeutronFloatingIPsNorthbound { + RestMessages.SERVICEUNAVAILABLE.toString()); } if (!floatingIPInterface.floatingIPExists(floatingipUUID)) - return Response.status(404).build(); + throw new ResourceNotFoundException("Floating IP UUID doesn't exist."); // TODO: need to undo port association if it exists NeutronFloatingIP singleton = floatingIPInterface.getFloatingIP(floatingipUUID); Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null); diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java index c08ee80e24..d7437c831d 100644 --- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java @@ -33,12 +33,15 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD; import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces; import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork; import org.opendaylight.controller.northbound.commons.RestMessages; +import org.opendaylight.controller.northbound.commons.exception.BadRequestException; +import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException; +import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException; import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException; import org.opendaylight.controller.sal.utils.ServiceHelper; /** - * Open DOVE Northbound REST APIs for Network.
    - * This class provides REST APIs for managing open DOVE internals related to Networks + * Neutron Northbound REST APIs for Network.
    + * This class provides REST APIs for managing neutron Networks * *
    *
    @@ -154,7 +157,7 @@ public class NeutronNetworksNorthbound { + RestMessages.SERVICEUNAVAILABLE.toString()); } if (!networkInterface.networkExists(netUUID)) { - return Response.status(404).build(); + throw new ResourceNotFoundException("network UUID does not exist."); } if (fields.size() > 0) { NeutronNetwork ans = networkInterface.getNetwork(netUUID); @@ -189,7 +192,7 @@ public class NeutronNetworksNorthbound { * network ID can't already exist */ if (networkInterface.networkExists(singleton.getID())) { - return Response.status(400).build(); + throw new BadRequestException("network UUID already exists"); } Object[] instances = ServiceHelper.getGlobalInstances(INeutronNetworkAware.class, this, null); @@ -226,10 +229,10 @@ public class NeutronNetworksNorthbound { * already in this bulk request */ if (networkInterface.networkExists(test.getID())) { - return Response.status(400).build(); + throw new BadRequestException("network UUID already exists"); } if (testMap.containsKey(test.getID())) { - return Response.status(400).build(); + throw new BadRequestException("network UUID already exists"); } if (instances != null) { for (Object instance: instances) { @@ -285,10 +288,10 @@ public class NeutronNetworksNorthbound { * network has to exist and only a single delta is supported */ if (!networkInterface.networkExists(netUUID)) { - return Response.status(404).build(); + throw new ResourceNotFoundException("network UUID does not exist."); } if (!input.isSingleton()) { - return Response.status(400).build(); + throw new BadRequestException("only singleton edits supported"); } NeutronNetwork delta = input.getSingleton(); @@ -297,7 +300,7 @@ public class NeutronNetworksNorthbound { */ if (delta.getID() != null || delta.getTenantID() != null || delta.getStatus() != null) { - return Response.status(400).build(); + throw new BadRequestException("attribute edit blocked by Neutron"); } Object[] instances = ServiceHelper.getGlobalInstances(INeutronNetworkAware.class, this, null); @@ -347,10 +350,10 @@ public class NeutronNetworksNorthbound { * network has to exist and not be in use before it can be removed */ if (!networkInterface.networkExists(netUUID)) { - return Response.status(404).build(); + throw new ResourceNotFoundException("network UUID does not exist."); } if (networkInterface.networkInUse(netUUID)) { - return Response.status(409).build(); + throw new ResourceConflictException("Network ID in use"); } NeutronNetwork singleton = networkInterface.getNetwork(netUUID); diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java index c26e0229d0..9f24e79ea0 100644 --- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java @@ -36,12 +36,15 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronPort; import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet; import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs; import org.opendaylight.controller.northbound.commons.RestMessages; +import org.opendaylight.controller.northbound.commons.exception.BadRequestException; +import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException; +import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException; import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException; import org.opendaylight.controller.sal.utils.ServiceHelper; /** - * Open DOVE Northbound REST APIs.
    - * This class provides REST APIs for managing the open DOVE + * Neutron Northbound REST APIs.
    + * This class provides REST APIs for managing neutron port objects * *
    *
    @@ -148,7 +151,7 @@ public class NeutronPortsNorthbound { + RestMessages.SERVICEUNAVAILABLE.toString()); } if (!portInterface.portExists(portUUID)) { - return Response.status(404).build(); + throw new ResourceNotFoundException("port UUID does not exist."); } if (fields.size() > 0) { NeutronPort ans = portInterface.getPort(portUUID); @@ -200,20 +203,20 @@ public class NeutronPortsNorthbound { * have a valid MAC and the MAC not be in use */ if (singleton.getNetworkUUID() == null) { - return Response.status(400).build(); + throw new BadRequestException("network UUID musy be specified"); } if (portInterface.portExists(singleton.getID())) { - return Response.status(400).build(); + throw new BadRequestException("port UUID already exists"); } if (!networkInterface.networkExists(singleton.getNetworkUUID())) { - return Response.status(404).build(); + throw new ResourceNotFoundException("network UUID does not exist."); } if (singleton.getMacAddress() == null || !singleton.getMacAddress().matches(mac_regex)) { - return Response.status(400).build(); + throw new BadRequestException("MAC address not properly formatted"); } if (portInterface.macInUse(singleton.getMacAddress())) { - return Response.status(409).build(); + throw new ResourceConflictException("MAC Address is in use."); } Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null); if (instances != null) { @@ -237,21 +240,21 @@ public class NeutronPortsNorthbound { while (fixedIPIterator.hasNext()) { Neutron_IPs ip = fixedIPIterator.next(); if (ip.getSubnetUUID() == null) { - return Response.status(400).build(); + throw new BadRequestException("subnet UUID not specified"); } if (!subnetInterface.subnetExists(ip.getSubnetUUID())) { - return Response.status(400).build(); + throw new BadRequestException("subnet UUID must exists"); } NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID()); if (!singleton.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) { - return Response.status(400).build(); + throw new BadRequestException("network UUID must match that of subnet"); } if (ip.getIpAddress() != null) { if (!subnet.isValidIP(ip.getIpAddress())) { - return Response.status(400).build(); + throw new BadRequestException("IP address is not valid"); } if (subnet.isIPInUse(ip.getIpAddress())) { - return Response.status(409).build(); + throw new ResourceConflictException("IP address is in use."); } } } @@ -279,32 +282,32 @@ public class NeutronPortsNorthbound { * can't already contain a new port with the same UUID */ if (portInterface.portExists(test.getID())) { - return Response.status(400).build(); + throw new BadRequestException("port UUID already exists"); } if (testMap.containsKey(test.getID())) { - return Response.status(400).build(); + throw new BadRequestException("port UUID already exists"); } for (NeutronPort check : testMap.values()) { if (test.getMacAddress().equalsIgnoreCase(check.getMacAddress())) { - return Response.status(409).build(); + throw new ResourceConflictException("MAC address already allocated"); } for (Neutron_IPs test_fixedIP : test.getFixedIPs()) { for (Neutron_IPs check_fixedIP : check.getFixedIPs()) { if (test_fixedIP.getIpAddress().equals(check_fixedIP.getIpAddress())) { - return Response.status(409).build(); + throw new ResourceConflictException("IP address already allocated"); } } } } testMap.put(test.getID(), test); if (!networkInterface.networkExists(test.getNetworkUUID())) { - return Response.status(404).build(); + throw new ResourceNotFoundException("network UUID does not exist."); } if (!test.getMacAddress().matches(mac_regex)) { - return Response.status(400).build(); + throw new BadRequestException("MAC address not properly formatted"); } if (portInterface.macInUse(test.getMacAddress())) { - return Response.status(409).build(); + throw new ResourceConflictException("MAC address in use"); } if (instances != null) { for (Object instance : instances) { @@ -327,23 +330,23 @@ public class NeutronPortsNorthbound { while (fixedIPIterator.hasNext()) { Neutron_IPs ip = fixedIPIterator.next(); if (ip.getSubnetUUID() == null) { - return Response.status(400).build(); + throw new BadRequestException("subnet UUID must be specified"); } if (!subnetInterface.subnetExists(ip.getSubnetUUID())) { - return Response.status(400).build(); + throw new BadRequestException("subnet UUID doesn't exists"); } NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID()); if (!test.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) { - return Response.status(400).build(); + throw new BadRequestException("network UUID must match that of subnet"); } if (ip.getIpAddress() != null) { if (!subnet.isValidIP(ip.getIpAddress())) { - return Response.status(400).build(); + throw new BadRequestException("ip address not valid"); } //TODO: need to add consideration for a fixed IP being assigned the same address as a allocated IP in the //same bulk create if (subnet.isIPInUse(ip.getIpAddress())) { - return Response.status(409).build(); + throw new ResourceConflictException("IP address in use"); } } } @@ -399,11 +402,11 @@ public class NeutronPortsNorthbound { // port has to exist and only a single delta is supported if (!portInterface.portExists(portUUID)) { - return Response.status(404).build(); + throw new ResourceNotFoundException("port UUID does not exist."); } NeutronPort target = portInterface.getPort(portUUID); if (!input.isSingleton()) { - return Response.status(400).build(); + throw new BadRequestException("only singleton edit suported"); } NeutronPort singleton = input.getSingleton(); NeutronPort original = portInterface.getPort(portUUID); @@ -411,7 +414,7 @@ public class NeutronPortsNorthbound { // deltas restricted by Neutron if (singleton.getID() != null || singleton.getTenantID() != null || singleton.getStatus() != null) { - return Response.status(400).build(); + throw new BadRequestException("attribute change blocked by Neutron"); } Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null); @@ -432,21 +435,21 @@ public class NeutronPortsNorthbound { while (fixedIPIterator.hasNext()) { Neutron_IPs ip = fixedIPIterator.next(); if (ip.getSubnetUUID() == null) { - return Response.status(400).build(); + throw new BadRequestException("subnet UUID must be specified"); } if (!subnetInterface.subnetExists(ip.getSubnetUUID())) { - return Response.status(400).build(); + throw new BadRequestException("subnet UUID doesn't exist."); } NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID()); if (!target.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) { - return Response.status(400).build(); + throw new BadRequestException("network UUID must match that of subnet"); } if (ip.getIpAddress() != null) { if (!subnet.isValidIP(ip.getIpAddress())) { - return Response.status(400).build(); + throw new BadRequestException("invalid IP address"); } if (subnet.isIPInUse(ip.getIpAddress())) { - return Response.status(409).build(); + throw new ResourceConflictException("IP address in use"); } } } @@ -454,7 +457,7 @@ public class NeutronPortsNorthbound { // TODO: Support change of security groups // update the port and return the modified object - portInterface.updatePort(portUUID, singleton); + portInterface.updatePort(portUUID, singleton); NeutronPort updatedPort = portInterface.getPort(portUUID); if (instances != null) { for (Object instance : instances) { @@ -488,7 +491,7 @@ public class NeutronPortsNorthbound { // port has to exist and not be owned by anyone. then it can be removed from the cache if (!portInterface.portExists(portUUID)) { - return Response.status(404).build(); + throw new ResourceNotFoundException("port UUID does not exist."); } NeutronPort port = portInterface.getPort(portUUID); if (port.getDeviceID() != null || diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java index fc7e0f7efb..17b2fcfcf9 100644 --- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java @@ -37,13 +37,16 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronRouter; import org.opendaylight.controller.networkconfig.neutron.NeutronRouter_Interface; import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet; import org.opendaylight.controller.northbound.commons.RestMessages; +import org.opendaylight.controller.northbound.commons.exception.BadRequestException; +import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException; +import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException; import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException; import org.opendaylight.controller.sal.utils.ServiceHelper; /** - * Open DOVE Northbound REST APIs.
    - * This class provides REST APIs for managing the open DOVE + * Neutron Northbound REST APIs.
    + * This class provides REST APIs for managing neutron routers * *
    *
    @@ -141,8 +144,9 @@ public class NeutronRoutersNorthbound { throw new ServiceUnavailableException("Router CRUD Interface " + RestMessages.SERVICEUNAVAILABLE.toString()); } - if (!routerInterface.routerExists(routerUUID)) - return Response.status(404).build(); + if (!routerInterface.routerExists(routerUUID)) { + throw new ResourceNotFoundException("Router UUID not found"); + } if (fields.size() > 0) { NeutronRouter ans = routerInterface.getRouter(routerUUID); return Response.status(200).entity( @@ -184,14 +188,14 @@ public class NeutronRoutersNorthbound { * exists and has been designated as "router:external" */ if (routerInterface.routerExists(singleton.getID())) - return Response.status(400).build(); + throw new BadRequestException("router UUID already exists"); if (singleton.getExternalGatewayInfo() != null) { String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID(); if (!networkInterface.networkExists(externNetworkPtr)) - return Response.status(400).build(); + throw new BadRequestException("External Network Pointer doesn't exist"); NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr); if (!externNetwork.isRouterExternal()) - return Response.status(400).build(); + throw new BadRequestException("External Network Pointer isn't marked as router:external"); } Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null); if (instances != null) { @@ -218,7 +222,7 @@ public class NeutronRoutersNorthbound { /* * only singleton router creates supported */ - return Response.status(400).build(); + throw new BadRequestException("Only singleton router creates supported"); } return Response.status(201).entity(input).build(); } @@ -256,9 +260,9 @@ public class NeutronRoutersNorthbound { * router has to exist and only a single delta can be supplied */ if (!routerInterface.routerExists(routerUUID)) - return Response.status(404).build(); + throw new ResourceNotFoundException("Router UUID not found"); if (!input.isSingleton()) - return Response.status(400).build(); + throw new BadRequestException("Only single router deltas supported"); NeutronRouter singleton = input.getSingleton(); NeutronRouter original = routerInterface.getRouter(routerUUID); @@ -267,7 +271,7 @@ public class NeutronRoutersNorthbound { */ if (singleton.getID() != null || singleton.getTenantID() != null || singleton.getStatus() != null) - return Response.status(400).build(); + throw new BadRequestException("Request attribute change not allowed"); Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null); if (instances != null) { @@ -285,10 +289,10 @@ public class NeutronRoutersNorthbound { if (singleton.getExternalGatewayInfo() != null) { String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID(); if (!networkInterface.networkExists(externNetworkPtr)) - return Response.status(400).build(); + throw new BadRequestException("External Network Pointer does not exist"); NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr); if (!externNetwork.isRouterExternal()) - return Response.status(400).build(); + throw new BadRequestException("External Network Pointer isn't marked as router:external"); } /* @@ -330,9 +334,9 @@ public class NeutronRoutersNorthbound { * verify that the router exists and is not in use before removing it */ if (!routerInterface.routerExists(routerUUID)) - return Response.status(404).build(); + throw new ResourceNotFoundException("Router UUID not found"); if (routerInterface.routerInUse(routerUUID)) - return Response.status(409).build(); + throw new ResourceConflictException("Router UUID in Use"); NeutronRouter singleton = routerInterface.getRouter(routerUUID); Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null); if (instances != null) { @@ -393,28 +397,27 @@ public class NeutronRoutersNorthbound { * or a port id, but not both, this code assumes that the plugin has filled everything in for us and so both must be present */ if (!routerInterface.routerExists(routerUUID)) - return Response.status(400).build(); + throw new BadRequestException("Router UUID doesn't exist"); NeutronRouter target = routerInterface.getRouter(routerUUID); if (input.getSubnetUUID() == null || input.getPortUUID() == null) - return Response.status(400).build(); + throw new BadRequestException("Must specify at subnet id, port id or both"); // check that the port is part of the subnet NeutronSubnet targetSubnet = subnetInterface.getSubnet(input.getSubnetUUID()); if (targetSubnet == null) - return Response.status(400).build(); + throw new BadRequestException("Subnet id doesn't exist"); NeutronPort targetPort = portInterface.getPort(input.getPortUUID()); if (targetPort == null) - return Response.status(400).build(); + throw new BadRequestException("Port id doesn't exist"); if (!targetSubnet.getPortsInSubnet().contains(targetPort)) - return Response.status(400).build(); + throw new BadRequestException("Port id not part of subnet id"); if (targetPort.getFixedIPs().size() != 1) - return Response.status(400).build(); + throw new BadRequestException("Port id must have a single fixedIP address"); if (targetPort.getDeviceID() != null || targetPort.getDeviceOwner() != null) - return Response.status(409).build(); - + throw new ResourceConflictException("Target Port already allocated"); Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null); if (instances != null) { for (Object instance : instances) { @@ -475,7 +478,7 @@ public class NeutronRoutersNorthbound { // verify the router exists if (!routerInterface.routerExists(routerUUID)) - return Response.status(400).build(); + throw new BadRequestException("Router does not exist"); NeutronRouter target = routerInterface.getRouter(routerUUID); /* @@ -486,7 +489,7 @@ public class NeutronRoutersNorthbound { input.getSubnetUUID() != null) { NeutronPort port = portInterface.getGatewayPort(input.getSubnetUUID()); if (port == null) - return Response.status(404).build(); + throw new ResourceNotFoundException("Port UUID not found"); input.setPortUUID(port.getID()); input.setID(target.getID()); input.setTenantID(target.getTenantID()); @@ -543,9 +546,18 @@ public class NeutronRoutersNorthbound { if (input.getPortUUID() != null && input.getSubnetUUID() != null) { NeutronPort port = portInterface.getPort(input.getPortUUID()); + if (port == null) { + throw new ResourceNotFoundException("Port UUID not found"); + } + if (port.getFixedIPs() == null) { + throw new ResourceNotFoundException("Port UUID jas no fixed IPs"); + } NeutronSubnet subnet = subnetInterface.getSubnet(input.getSubnetUUID()); + if (subnet == null) { + throw new ResourceNotFoundException("Subnet UUID not found"); + } if (!subnet.isValidIP(port.getFixedIPs().get(0).getIpAddress())) - return Response.status(409).build(); + throw new ResourceConflictException("Target Port IP not in Target Subnet"); input.setID(target.getID()); input.setTenantID(target.getTenantID()); Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null); @@ -566,6 +578,6 @@ public class NeutronRoutersNorthbound { } // have to specify either a port ID or a subnet ID - return Response.status(400).build(); + throw new BadRequestException("Must specify port id or subnet id or both"); } } diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java index dffac55c50..224fcb5f01 100644 --- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java @@ -33,13 +33,16 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD; import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces; import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet; import org.opendaylight.controller.northbound.commons.RestMessages; +import org.opendaylight.controller.northbound.commons.exception.BadRequestException; +import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException; +import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException; import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException; import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException; import org.opendaylight.controller.sal.utils.ServiceHelper; /** - * Open DOVE Northbound REST APIs.
    - * This class provides REST APIs for managing open DOVE internals related to Subnets + * Neutron Northbound REST APIs for Subnets.
    + * This class provides REST APIs for managing neutron Subnets * *
    *
    @@ -142,7 +145,7 @@ public class NeutronSubnetsNorthbound { + RestMessages.SERVICEUNAVAILABLE.toString()); } if (!subnetInterface.subnetExists(subnetUUID)) { - return Response.status(404).build(); + throw new ResourceNotFoundException("subnet UUID does not exist."); } if (fields.size() > 0) { NeutronSubnet ans = subnetInterface.getSubnet(subnetUUID); @@ -190,19 +193,19 @@ public class NeutronSubnetsNorthbound { * *then* add the subnet to the cache */ if (subnetInterface.subnetExists(singleton.getID())) { - return Response.status(400).build(); + throw new BadRequestException("subnet UUID already exists"); } if (!networkInterface.networkExists(singleton.getNetworkUUID())) { - return Response.status(404).build(); + throw new ResourceNotFoundException("network UUID does not exist."); } if (!singleton.isValidCIDR()) { - return Response.status(400).build(); + throw new BadRequestException("invaild CIDR"); } if (!singleton.initDefaults()) { throw new InternalServerErrorException("subnet object could not be initialized properly"); } if (singleton.gatewayIP_Pool_overlap()) { - return Response.status(409).build(); + throw new ResourceConflictException("IP pool overlaps with gateway"); } Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null); if (instances != null) { @@ -240,20 +243,20 @@ public class NeutronSubnetsNorthbound { throw new InternalServerErrorException("subnet object could not be initialized properly"); } if (subnetInterface.subnetExists(test.getID())) { - return Response.status(400).build(); + throw new BadRequestException("subnet UUID already exists"); } if (testMap.containsKey(test.getID())) { - return Response.status(400).build(); + throw new BadRequestException("subnet UUID already exists"); } testMap.put(test.getID(), test); if (!networkInterface.networkExists(test.getNetworkUUID())) { - return Response.status(404).build(); + throw new ResourceNotFoundException("network UUID does not exist."); } if (!test.isValidCIDR()) { - return Response.status(400).build(); + throw new BadRequestException("Invalid CIDR"); } if (test.gatewayIP_Pool_overlap()) { - return Response.status(409).build(); + throw new ResourceConflictException("IP pool overlaps with gateway"); } if (instances != null) { for (Object instance : instances) { @@ -312,10 +315,10 @@ public class NeutronSubnetsNorthbound { * verify the subnet exists and there is only one delta provided */ if (!subnetInterface.subnetExists(subnetUUID)) { - return Response.status(404).build(); + throw new ResourceNotFoundException("subnet UUID does not exist."); } if (!input.isSingleton()) { - return Response.status(400).build(); + throw new BadRequestException("Only singleton edit supported"); } NeutronSubnet delta = input.getSingleton(); NeutronSubnet original = subnetInterface.getSubnet(subnetUUID); @@ -326,7 +329,7 @@ public class NeutronSubnetsNorthbound { if (delta.getID() != null || delta.getTenantID() != null || delta.getIpVersion() != null || delta.getCidr() != null || delta.getAllocationPools() != null) { - return Response.status(400).build(); + throw new BadRequestException("Attribute edit blocked by Neutron"); } Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null); @@ -378,7 +381,7 @@ public class NeutronSubnetsNorthbound { * verify the subnet exists and it isn't currently in use */ if (!subnetInterface.subnetExists(subnetUUID)) { - return Response.status(404).build(); + throw new ResourceNotFoundException("subnet UUID does not exist."); } if (subnetInterface.subnetInUse(subnetUUID)) { return Response.status(409).build(); diff --git a/opendaylight/sal/api/pom.xml b/opendaylight/sal/api/pom.xml index 16868f5517..326755309d 100644 --- a/opendaylight/sal/api/pom.xml +++ b/opendaylight/sal/api/pom.xml @@ -15,7 +15,7 @@ sal - 0.7.1-SNAPSHOT + 0.8.1-SNAPSHOT bundle diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Edge.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Edge.java index 7f398db6f1..0dffee9c47 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Edge.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Edge.java @@ -85,6 +85,19 @@ public class Edge implements Serializable { } } + /** + * Create the reversed edge + * @return The reversed edge. + */ + public Edge reverse() { + Edge re; + try { + re = new Edge(this.headNodeConnector, this.tailNodeConnector); + } catch (ConstructionException e) { + re = null; + } + return re; + } /** * getter of edge * diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java index 31b3ec6a5a..ba2394131d 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java @@ -17,6 +17,8 @@ package org.opendaylight.controller.sal.core; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -81,6 +83,39 @@ public class Path implements Serializable { this.edges = edges; } + /** + * Create the reversed path + * @return The reversed path + */ + public Path reverse() { + int j = edges.size(); // size always > 0 + Edge[] aEdges = new Edge[j]; + for (Edge e : edges) { + j--; + aEdges[j] = e.reverse(); + } + Path rp; + try { + rp = new Path(Arrays.asList(aEdges)); + } catch (ConstructionException ce) { + rp = null; + } + return rp; + } + + /** + * Return the list of nodes of this path, the first node is the start node + * @return the list of nodes + */ + public List getNodes() { + List nl = new ArrayList(); + nl.add(this.getStartNode()); + for (Edge e : edges) { + nl.add(e.getHeadNodeConnector().getNode()); + } + return nl; + } + /** * Copy Construct for a path *