From: Tony Tkacik Date: Mon, 17 Feb 2014 16:31:35 +0000 (+0000) Subject: Merge "CHange log level from warn to debug in ProtocolSessionPromise when connection... X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~425 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=082d7ba433b85d5810c50f624d2691088336e66a;hp=8573aed70f94620462436b1c9e38f8becaa61d5b Merge "CHange log level from warn to debug in ProtocolSessionPromise when connection attempt fails" --- diff --git a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPReply.java b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPReply.java index e4388c598f..a6ee60f65d 100644 --- a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPReply.java +++ b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPReply.java @@ -18,7 +18,7 @@ import org.opendaylight.controller.sal.utils.HexEncode; * ARP Reply event wrapper */ public class ARPReply extends ARPEvent { - + private static final long serialVersionUID = 1L; private final NodeConnector port; private final byte[] tMac; private final byte[] sMac; diff --git a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPRequest.java b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPRequest.java index 1b125ddeb2..051635ad53 100644 --- a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPRequest.java +++ b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPRequest.java @@ -19,6 +19,7 @@ import org.opendaylight.controller.switchmanager.Subnet; * specified host */ public class ARPRequest extends ARPEvent { + private static final long serialVersionUID = 1L; private final Subnet subnet; private final HostNodeConnector host; diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index 93845a356d..0d74b99ce1 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -673,6 +673,11 @@ ietf-topology ${ietf-topology.version} + + org.opendaylight.yangtools.model + ietf-topology-l3-unicast-igp + ${ietf-topology.version} + org.opendaylight.yangtools.model opendaylight-l2-types @@ -694,6 +699,16 @@ concepts ${yangtools.version} + + org.opendaylight.yangtools + restconf-client-api + ${yangtools.version} + + + org.opendaylight.yangtools + restconf-client-impl + ${yangtools.version} + @@ -1204,6 +1219,13 @@ sal-binding-broker-impl ${mdsal.version} + + org.opendaylight.controller + sal-binding-broker-impl + ${mdsal.version} + test-jar + test + org.opendaylight.controller sal-compatibility @@ -1269,6 +1291,21 @@ statistics-manager ${mdsal.version} + + org.opendaylight.controller + sal-remote + ${mdsal.version} + + + org.opendaylight.controller + sal-restconf-broker + ${mdsal.version} + + + org.opendaylight.controller + sal-binding-util + ${mdsal.version} + org.opendaylight.controller concepts @@ -1405,6 +1442,16 @@ config-persister-impl ${netconf.version} + + ${project.groupId} + ietf-netconf-monitoring + ${netconf.version} + + + ${project.groupId} + ietf-netconf-monitoring-extension + ${netconf.version} + diff --git a/opendaylight/config/config-manager/pom.xml b/opendaylight/config/config-manager/pom.xml index f50f7693ad..52377ae025 100644 --- a/opendaylight/config/config-manager/pom.xml +++ b/opendaylight/config/config-manager/pom.xml @@ -65,12 +65,10 @@ org.opendaylight.yangtools concepts - ${yangtools.version} org.opendaylight.yangtools yang-data-impl - ${yangtools.version} diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml b/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml index 301f00f768..92f7e27788 100644 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml +++ b/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml @@ -28,12 +28,10 @@ org.opendaylight.controller config-persister-directory-adapter - ${config.version} org.opendaylight.controller config-persister-directory-xml-adapter - ${config.version} diff --git a/opendaylight/config/config-persister-directory-xml-adapter/pom.xml b/opendaylight/config/config-persister-directory-xml-adapter/pom.xml index 36fa530062..2c5d2359a0 100644 --- a/opendaylight/config/config-persister-directory-xml-adapter/pom.xml +++ b/opendaylight/config/config-persister-directory-xml-adapter/pom.xml @@ -28,7 +28,6 @@ org.opendaylight.controller config-persister-file-xml-adapter - ${config.version} diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java index 4c99c7770a..13043458c0 100644 --- a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java +++ b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java @@ -47,7 +47,7 @@ public class ConfigRegistryClientsTest { @Test public void testLookupRuntimeBeans() throws Exception { Set jmxLookup = lookupRuntimeBeans(jmxRegistryClient); - assertEquals(Sets.newHashSet(testingRegistry.run2, testingRegistry.run1, testingRegistry.run3), jmxLookup); + assertEquals(Sets.newHashSet(TestingConfigRegistry.run2, TestingConfigRegistry.run1, TestingConfigRegistry.run3), jmxLookup); } private Set lookupRuntimeBeans(ConfigRegistryClient client) @@ -67,13 +67,13 @@ public class ConfigRegistryClientsTest { jmxRegistryClient, TestingConfigRegistry.moduleName1, TestingConfigRegistry.instName1); assertEquals(1, jmxLookup.size()); - assertEquals(Sets.newHashSet(testingRegistry.run2), jmxLookup); + assertEquals(Sets.newHashSet(TestingConfigRegistry.run2), jmxLookup); jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance( jmxRegistryClient, TestingConfigRegistry.moduleName2, TestingConfigRegistry.instName2); assertEquals(1, jmxLookup.size()); - assertEquals(Sets.newHashSet(testingRegistry.run3), jmxLookup); + assertEquals(Sets.newHashSet(TestingConfigRegistry.run3), jmxLookup); jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance( jmxRegistryClient, TestingConfigRegistry.moduleName1, diff --git a/opendaylight/config/netty-event-executor-config/pom.xml b/opendaylight/config/netty-event-executor-config/pom.xml index c1e0ccae31..88afa13155 100644 --- a/opendaylight/config/netty-event-executor-config/pom.xml +++ b/opendaylight/config/netty-event-executor-config/pom.xml @@ -24,7 +24,6 @@ org.opendaylight.controller netty-config-api - ${project.version} org.slf4j diff --git a/opendaylight/config/netty-threadgroup-config/pom.xml b/opendaylight/config/netty-threadgroup-config/pom.xml index 2e7777f91b..172fe7f1fc 100644 --- a/opendaylight/config/netty-threadgroup-config/pom.xml +++ b/opendaylight/config/netty-threadgroup-config/pom.xml @@ -26,7 +26,6 @@ org.opendaylight.controller netty-config-api - ${project.version} org.slf4j diff --git a/opendaylight/config/netty-timer-config/pom.xml b/opendaylight/config/netty-timer-config/pom.xml index 1e0c917032..9d3b5505ce 100644 --- a/opendaylight/config/netty-timer-config/pom.xml +++ b/opendaylight/config/netty-timer-config/pom.xml @@ -24,12 +24,10 @@ org.opendaylight.controller netty-config-api - ${project.version} org.opendaylight.controller threadpool-config-api - ${project.version} org.slf4j @@ -65,7 +63,6 @@ org.opendaylight.controller threadpool-config-impl - ${project.version} test diff --git a/opendaylight/config/pom.xml b/opendaylight/config/pom.xml index 80621a4d44..3474740ca1 100644 --- a/opendaylight/config/pom.xml +++ b/opendaylight/config/pom.xml @@ -80,7 +80,6 @@ ch.qos.logback logback-classic - ${logback.version} test @@ -420,4 +419,4 @@ - \ No newline at end of file + diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java index 5bcc5402af..0cc950af65 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java @@ -7,52 +7,16 @@ */ package org.opendaylight.controller.config.yangjmxgenerator; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Optional; -import com.google.common.collect.Sets; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute; + import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc; -import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute; -import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute; -import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute; -import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute; -import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute; import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper; -import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException; -import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; -import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; -import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; -import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; -import org.opendaylight.yangtools.yang.model.api.ModuleImport; -import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; -import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; -import org.opendaylight.yangtools.yang.model.api.UsesNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static java.lang.String.format; -import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName; /** * Represents part of yang model that describes a module. @@ -96,67 +60,34 @@ import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstant *

*/ public class ModuleMXBeanEntry extends AbstractEntry { - private static final Logger logger = LoggerFactory - .getLogger(ModuleMXBeanEntry.class); - - // TODO: the XPath should be parsed by code generator IMO - private static final String MAGIC_STRING = "MAGIC_STRING"; - private static final String MODULE_CONDITION_XPATH_TEMPLATE = "^/MAGIC_STRING:modules/MAGIC_STRING:module/MAGIC_STRING:type\\s*=\\s*['\"](.+)['\"]$"; - private static final SchemaPath expectedConfigurationAugmentationSchemaPath = new SchemaPath( - Arrays.asList(createConfigQName("modules"), - createConfigQName("module"), - createConfigQName("configuration")), true); - private static final SchemaPath expectedStateAugmentationSchemaPath = new SchemaPath( - Arrays.asList(createConfigQName("modules"), - createConfigQName("module"), createConfigQName("state")), - true); - - private static final Pattern PREFIX_COLON_LOCAL_NAME = Pattern - .compile("^(.+):(.+)$"); private static final String MODULE_SUFFIX = "Module"; private static final String FACTORY_SUFFIX = MODULE_SUFFIX + "Factory"; private static final String CLASS_NAME_SUFFIX = MODULE_SUFFIX + "MXBean"; private static final String ABSTRACT_PREFIX = "Abstract"; - /* - * threadpool-dynamic from the example above, taken from when condition, not - * the case name - */ - private final String globallyUniqueName; + private final ModuleMXBeanEntryInitial initial; private Map yangToAttributes; - private final String nullableDescription, packageName, javaNamePrefix, - namespace; - private final Map providedServices; private Collection runtimeBeans; - private final QName yangModuleQName; - - public ModuleMXBeanEntry(IdentitySchemaNode id, - Map yangToAttributes, String packageName, - Map providedServices2, String javaNamePrefix, - String namespace, Collection runtimeBeans, - QName yangModuleQName) { - this.globallyUniqueName = id.getQName().getLocalName(); + + ModuleMXBeanEntry(ModuleMXBeanEntryInitial initials, Map yangToAttributes, + Map providedServices2, Collection runtimeBeans) { this.yangToAttributes = yangToAttributes; - this.nullableDescription = id.getDescription(); - this.packageName = packageName; - this.javaNamePrefix = checkNotNull(javaNamePrefix); - this.namespace = checkNotNull(namespace); this.providedServices = Collections.unmodifiableMap(providedServices2); this.runtimeBeans = runtimeBeans; - this.yangModuleQName = yangModuleQName; + this.initial = initials; } public String getMXBeanInterfaceName() { - return javaNamePrefix + CLASS_NAME_SUFFIX; + return initial.javaNamePrefix + CLASS_NAME_SUFFIX; } public String getStubFactoryName() { - return javaNamePrefix + FACTORY_SUFFIX; + return initial.javaNamePrefix + FACTORY_SUFFIX; } public String getAbstractFactoryName() { @@ -164,7 +95,7 @@ public class ModuleMXBeanEntry extends AbstractEntry { } public String getStubModuleName() { - return javaNamePrefix + MODULE_SUFFIX; + return initial.javaNamePrefix + MODULE_SUFFIX; } public String getAbstractModuleName() { @@ -172,16 +103,16 @@ public class ModuleMXBeanEntry extends AbstractEntry { } public String getFullyQualifiedName(String typeName) { - return FullyQualifiedNameHelper.getFullyQualifiedName(packageName, + return FullyQualifiedNameHelper.getFullyQualifiedName(initial.packageName, typeName); } public String getGloballyUniqueName() { - return globallyUniqueName; + return initial.localName; } public String getPackageName() { - return packageName; + return initial.packageName; } /** @@ -202,31 +133,11 @@ public class ModuleMXBeanEntry extends AbstractEntry { } public String getJavaNamePrefix() { - return javaNamePrefix; + return initial.javaNamePrefix; } public String getNamespace() { - return namespace; - } - - @VisibleForTesting - static Matcher getWhenConditionMatcher(String prefix, - RevisionAwareXPath whenConstraint) { - String xpathRegex = MODULE_CONDITION_XPATH_TEMPLATE.replace( - MAGIC_STRING, prefix); - Pattern pattern = Pattern.compile(xpathRegex); - return pattern.matcher(whenConstraint.toString()); - } - - static String getConfigModulePrefixFromImport(Module currentModule) { - for (ModuleImport currentImport : currentModule.getImports()) { - if (currentImport.getModuleName().equals( - ConfigConstants.CONFIG_MODULE)) { - return currentImport.getPrefix(); - } - } - throw new IllegalArgumentException("Cannot find import " - + ConfigConstants.CONFIG_MODULE + " in " + currentModule); + return initial.namespace; } /** @@ -241,504 +152,93 @@ public class ModuleMXBeanEntry extends AbstractEntry { Map qNamesToSIEs, SchemaContext schemaContext, TypeProviderWrapper typeProviderWrapper, String packageName) { - Map uniqueGeneratedClassesNames = new HashMap<>(); - logger.debug("Generating ModuleMXBeans of {} to package {}", - currentModule.getNamespace(), packageName); - String configModulePrefix; - try { - configModulePrefix = getConfigModulePrefixFromImport(currentModule); - } catch (IllegalArgumentException e) { - // this module does not import config module - return Collections.emptyMap(); - } - // get identities of base config:module-type - Map moduleIdentities = new HashMap<>(); - - for (IdentitySchemaNode id : currentModule.getIdentities()) { - if (id.getBaseIdentity() != null - && ConfigConstants.MODULE_TYPE_Q_NAME.equals(id - .getBaseIdentity().getQName())) { - String identityLocalName = id.getQName().getLocalName(); - if (moduleIdentities.containsKey(identityLocalName)) { - throw new IllegalStateException( - "Module name already defined in this module: " - + identityLocalName); - } else { - moduleIdentities.put(identityLocalName, id); - logger.debug("Found identity {}", identityLocalName); - } - // validation check on unknown schema nodes - 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())) { - // 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 { - throw new IllegalStateException( - "Unexpected language extension " - + unknownNode.getNodeType()); - } - } - } - } - Map result = new HashMap<>(); - // each module name should have an augmentation defined - Map unaugmentedModuleIdentities = new HashMap<>( - moduleIdentities); - for (AugmentationSchema augmentation : currentModule.getAugmentations()) { - Set childNodes = augmentation.getChildNodes(); - if (childNodes.size() == 1) { - DataSchemaNode when = childNodes.iterator().next(); - if (when instanceof ChoiceCaseNode) { - ChoiceCaseNode choiceCaseNode = (ChoiceCaseNode) when; - if (choiceCaseNode.getConstraints() == null - || choiceCaseNode.getConstraints() - .getWhenCondition() == null) { - continue; - } - RevisionAwareXPath xPath = choiceCaseNode.getConstraints() - .getWhenCondition(); - Matcher matcher = getWhenConditionMatcher( - configModulePrefix, xPath); - if (matcher.matches() == false) { - continue; - } - String moduleLocalNameFromXPath = matcher.group(1); - IdentitySchemaNode moduleIdentity = moduleIdentities - .get(moduleLocalNameFromXPath); - unaugmentedModuleIdentities - .remove(moduleLocalNameFromXPath); - checkState(moduleIdentity != null, "Cannot find identity " - + moduleLocalNameFromXPath - + " matching augmentation " + augmentation); - Map providedServices = findProvidedServices( - moduleIdentity, currentModule, qNamesToSIEs, - schemaContext); - - if (moduleIdentity == null) { - throw new IllegalStateException( - "Cannot find identity specified by augmentation xpath constraint: " - + moduleLocalNameFromXPath + " of " - + augmentation); - } - String javaNamePrefix = findJavaNamePrefix(moduleIdentity); - - Map yangToAttributes = null; - // runtime-data - Collection runtimeBeans = null; - - if (expectedConfigurationAugmentationSchemaPath - .equals(augmentation.getTargetPath())) { - logger.debug("Parsing configuration of {}", - moduleLocalNameFromXPath); - yangToAttributes = fillConfiguration(choiceCaseNode, - currentModule, typeProviderWrapper, - qNamesToSIEs, schemaContext, packageName); - checkUniqueAttributesWithGeneratedClass( - uniqueGeneratedClassesNames, when.getQName(), - yangToAttributes); - } else if (expectedStateAugmentationSchemaPath - .equals(augmentation.getTargetPath())) { - logger.debug("Parsing state of {}", - moduleLocalNameFromXPath); - try { - runtimeBeans = fillRuntimeBeans(choiceCaseNode, - currentModule, typeProviderWrapper, - packageName, moduleLocalNameFromXPath, - javaNamePrefix); - } catch (NameConflictException e) { - throw new NameConflictException( - e.getConflictingName(), when.getQName(), - when.getQName()); - } - checkUniqueRuntimeBeansGeneratedClasses( - uniqueGeneratedClassesNames, when, runtimeBeans); - Set runtimeBeanEntryValues = Sets - .newHashSet(runtimeBeans); - for (RuntimeBeanEntry entry : runtimeBeanEntryValues) { - checkUniqueAttributesWithGeneratedClass( - uniqueGeneratedClassesNames, - when.getQName(), - entry.getYangPropertiesToTypesMap()); - } - - } else { - throw new IllegalArgumentException( - "Cannot parse augmentation " + augmentation); - } - if (result.containsKey(moduleLocalNameFromXPath)) { - // either fill runtimeBeans or yangToAttributes - ModuleMXBeanEntry moduleMXBeanEntry = result - .get(moduleLocalNameFromXPath); - if (yangToAttributes != null - && moduleMXBeanEntry.getAttributes() == null) { - moduleMXBeanEntry - .setYangToAttributes(yangToAttributes); - } else if (runtimeBeans != null - && moduleMXBeanEntry.getRuntimeBeans() == null) { - moduleMXBeanEntry.setRuntimeBeans(runtimeBeans); - } - } else { - // construct ModuleMXBeanEntry - ModuleMXBeanEntry moduleMXBeanEntry = new ModuleMXBeanEntry( - moduleIdentity, yangToAttributes, packageName, - providedServices, javaNamePrefix, currentModule - .getNamespace().toString(), - runtimeBeans, - ModuleUtil.getQName(currentModule)); - moduleMXBeanEntry.setYangModuleName(currentModule - .getName()); - moduleMXBeanEntry - .setYangModuleLocalname(moduleLocalNameFromXPath); - result.put(moduleLocalNameFromXPath, moduleMXBeanEntry); - } - } // skip if child node is not ChoiceCaseNode - } // skip if childNodes != 1 - } - // clean up nulls - for (Entry entry : result.entrySet()) { - ModuleMXBeanEntry module = entry.getValue(); - if (module.getAttributes() == null) { - module.setYangToAttributes(Collections - . emptyMap()); - } else if (module.getRuntimeBeans() == null) { - module.setRuntimeBeans(Collections - . emptyList()); - } - } - // check attributes name uniqueness - for (Entry entry : result.entrySet()) { - checkUniqueRuntimeBeanAttributesName(entry.getValue(), - uniqueGeneratedClassesNames); - } - if (unaugmentedModuleIdentities.size() > 0) { - logger.warn("Augmentation not found for all module identities: {}", - unaugmentedModuleIdentities.keySet()); - } + ModuleMXBeanEntryBuilder builder = new ModuleMXBeanEntryBuilder().setModule(currentModule).setqNamesToSIEs(qNamesToSIEs) + .setSchemaContext(schemaContext).setTypeProviderWrapper(typeProviderWrapper) + .setPackageName(packageName); - logger.debug("Number of ModuleMXBeans to be generated: {}", - result.size()); - return result; + return builder.build(); } - private static void checkUniqueRuntimeBeansGeneratedClasses( - Map uniqueGeneratedClassesNames, - DataSchemaNode when, Collection runtimeBeans) { - for (RuntimeBeanEntry runtimeBean : runtimeBeans) { - final String javaNameOfRuntimeMXBean = runtimeBean - .getJavaNameOfRuntimeMXBean(); - if (uniqueGeneratedClassesNames - .containsKey(javaNameOfRuntimeMXBean)) { - QName firstDefinedQName = uniqueGeneratedClassesNames - .get(javaNameOfRuntimeMXBean); - throw new NameConflictException(javaNameOfRuntimeMXBean, - firstDefinedQName, when.getQName()); - } - uniqueGeneratedClassesNames.put(javaNameOfRuntimeMXBean, - when.getQName()); - } - } - - private static void checkUniqueRuntimeBeanAttributesName( - ModuleMXBeanEntry mxBeanEntry, - Map uniqueGeneratedClassesNames) { - for (RuntimeBeanEntry runtimeBeanEntry : mxBeanEntry.getRuntimeBeans()) { - for (String runtimeAttName : runtimeBeanEntry - .getYangPropertiesToTypesMap().keySet()) { - if (mxBeanEntry.getAttributes().keySet() - .contains(runtimeAttName)) { - QName qName1 = uniqueGeneratedClassesNames - .get(runtimeBeanEntry.getJavaNameOfRuntimeMXBean()); - QName qName2 = uniqueGeneratedClassesNames.get(mxBeanEntry - .getGloballyUniqueName()); - throw new NameConflictException(runtimeAttName, qName1, - qName2); - } - } - } - } - - private static void checkUniqueAttributesWithGeneratedClass( - Map uniqueGeneratedClassNames, QName parentQName, - Map yangToAttributes) { - for (Entry attr : yangToAttributes.entrySet()) { - if (attr.getValue() instanceof TOAttribute) { - checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName, - (TOAttribute) attr.getValue()); - } else if (attr.getValue() instanceof ListAttribute - && ((ListAttribute) attr.getValue()).getInnerAttribute() instanceof TOAttribute) { - checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName, - (TOAttribute) ((ListAttribute) attr.getValue()) - .getInnerAttribute()); - } - } + public Map getAttributes() { + return yangToAttributes; } - private static void checkUniqueTOAttr( - Map uniqueGeneratedClassNames, QName parentQName, - TOAttribute attr) { - final String upperCaseCammelCase = attr.getUpperCaseCammelCase(); - if (uniqueGeneratedClassNames.containsKey(upperCaseCammelCase)) { - QName firstDefinedQName = uniqueGeneratedClassNames - .get(upperCaseCammelCase); - throw new NameConflictException(upperCaseCammelCase, - firstDefinedQName, parentQName); - } else { - uniqueGeneratedClassNames.put(upperCaseCammelCase, parentQName); - } + void setYangToAttributes(Map newAttributes) { + this.yangToAttributes = newAttributes; } - private static Collection fillRuntimeBeans( - ChoiceCaseNode choiceCaseNode, Module currentModule, - TypeProviderWrapper typeProviderWrapper, String packageName, - String moduleLocalNameFromXPath, String javaNamePrefix) { - - return RuntimeBeanEntry.extractClassNameToRuntimeBeanMap(packageName, - choiceCaseNode, moduleLocalNameFromXPath, typeProviderWrapper, - javaNamePrefix, currentModule).values(); - + public String getNullableDescription() { + return initial.description; } - private static Map fillConfiguration( - ChoiceCaseNode choiceCaseNode, Module currentModule, - TypeProviderWrapper typeProviderWrapper, - Map qNamesToSIEs, - SchemaContext schemaContext, String packageName) { - Map yangToAttributes = new HashMap<>(); - for (DataSchemaNode attrNode : choiceCaseNode.getChildNodes()) { - AttributeIfc attributeValue = getAttributeValue(attrNode, - currentModule, qNamesToSIEs, typeProviderWrapper, - schemaContext, packageName); - yangToAttributes.put(attributeValue.getAttributeYangName(), - attributeValue); - } - return yangToAttributes; + public QName getYangModuleQName() { + return initial.qName; } - private static Map findProvidedServices( - IdentitySchemaNode moduleIdentity, Module currentModule, - Map qNamesToSIEs, - SchemaContext schemaContext) { - Map result = new HashMap<>(); - for (UnknownSchemaNode unknownNode : moduleIdentity - .getUnknownSchemaNodes()) { - if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME - .equals(unknownNode.getNodeType())) { - String prefixAndIdentityLocalName = unknownNode - .getNodeParameter(); - ServiceInterfaceEntry sie = findSIE(prefixAndIdentityLocalName, - currentModule, qNamesToSIEs, schemaContext); - result.put(sie.getFullyQualifiedName(), sie.getQName()); - } - } - return result; + @Override + public String toString() { + return "ModuleMXBeanEntry{" + "globallyUniqueName='" + + initial.localName + '\'' + ", packageName='" + initial.packageName + + '\'' + '}'; } - /** - * For input node, find if it contains config:java-name-prefix extension. If - * not found, convert local name of node converted to cammel case. - */ - public static String findJavaNamePrefix(SchemaNode schemaNode) { - return convertToJavaName(schemaNode, true); - } + static final class ModuleMXBeanEntryInitial { - public static String findJavaParameter(SchemaNode schemaNode) { - return convertToJavaName(schemaNode, false); - } + private String localName; + private String description; + private String packageName; + private String javaNamePrefix; + private String namespace; + private QName qName; - public static String convertToJavaName(SchemaNode schemaNode, - boolean capitalizeFirstLetter) { - for (UnknownSchemaNode unknownNode : schemaNode.getUnknownSchemaNodes()) { - if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME - .equals(unknownNode.getNodeType())) { - String value = unknownNode.getNodeParameter(); - return convertToJavaName(value, capitalizeFirstLetter); - } + ModuleMXBeanEntryInitial(String localName, String description, String packageName, String javaNamePrefix, String namespace, QName qName) { + this.localName = localName; + this.description = description; + this.packageName = packageName; + this.javaNamePrefix = javaNamePrefix; + this.namespace = namespace; + this.qName = qName; } - return convertToJavaName(schemaNode.getQName().getLocalName(), - capitalizeFirstLetter); } - public static String convertToJavaName(String localName, - boolean capitalizeFirstLetter) { - if (capitalizeFirstLetter) { - return BindingGeneratorUtil.parseToClassName(localName); - } else { - return BindingGeneratorUtil.parseToValidParamName(localName); - } - } + static final class ModuleMXBeanEntryInitialBuilder { + private String localName; + private String description; + private String packageName; + private String javaNamePrefix; + private String namespace; + private QName qName; - private static int getChildNodeSizeWithoutUses(DataNodeContainer csn) { - int result = 0; - for (DataSchemaNode dsn : csn.getChildNodes()) { - if (dsn.isAddedByUses() == false) { - result++; - } + public ModuleMXBeanEntryInitialBuilder setPackageName(String packageName) { + this.packageName = packageName; + return this; } - return result; - } - private static AttributeIfc getAttributeValue(DataSchemaNode attrNode, - Module currentModule, - Map qNamesToSIEs, - TypeProviderWrapper typeProviderWrapper, - SchemaContext schemaContext, String packageName) { - - if (attrNode instanceof LeafSchemaNode) { - // simple type - LeafSchemaNode leaf = (LeafSchemaNode) attrNode; - return new JavaAttribute(leaf, typeProviderWrapper); - } else if (attrNode instanceof ContainerSchemaNode) { - // reference or TO - ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) attrNode; - Optional dependencyAttributeOptional = extractDependency( - containerSchemaNode, attrNode, currentModule, qNamesToSIEs, - schemaContext); - if (dependencyAttributeOptional.isPresent()) { - return dependencyAttributeOptional.get(); - } else { - return TOAttribute.create(containerSchemaNode, - typeProviderWrapper, packageName); - } - - } else if (attrNode instanceof LeafListSchemaNode) { - return ListAttribute.create((LeafListSchemaNode) attrNode, - typeProviderWrapper); - } else if (attrNode instanceof ListSchemaNode) { - ListSchemaNode listSchemaNode = (ListSchemaNode) attrNode; - Optional dependencyAttributeOptional = extractDependency( - listSchemaNode, attrNode, currentModule, qNamesToSIEs, - schemaContext); - if (dependencyAttributeOptional.isPresent()) { - return dependencyAttributeOptional.get(); - } else { - return ListAttribute.create(listSchemaNode, - typeProviderWrapper, packageName); - } - } else { - throw new UnsupportedOperationException( - "Unknown configuration node " + attrNode.toString()); + public ModuleMXBeanEntryInitialBuilder setJavaNamePrefix(String javaNamePrefix) { + this.javaNamePrefix = javaNamePrefix; + return this; } - } - private static Optional extractDependency( - DataNodeContainer dataNodeContainer, DataSchemaNode attrNode, - Module currentModule, - Map qNamesToSIEs, - SchemaContext schemaContext) { - if (dataNodeContainer.getUses().size() == 1 - && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) { - // reference - UsesNode usesNode = dataNodeContainer.getUses().iterator().next(); - checkState(usesNode.getRefines().size() == 1, - "Unexpected 'refine' child node size of " - + dataNodeContainer); - LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines() - .values().iterator().next(); - checkState(refine.getUnknownSchemaNodes().size() == 1, - "Unexpected unknown schema node size of " + refine); - UnknownSchemaNode requiredIdentity = refine.getUnknownSchemaNodes() - .iterator().next(); - checkState( - ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity - .getNodeType()), "Unexpected language extension " - + requiredIdentity); - String prefixAndIdentityLocalName = requiredIdentity - .getNodeParameter(); - // import should point to a module - ServiceInterfaceEntry serviceInterfaceEntry = findSIE( - prefixAndIdentityLocalName, currentModule, qNamesToSIEs, - schemaContext); - boolean mandatory = refine.getConstraints().isMandatory(); - AbstractDependencyAttribute reference; - if (dataNodeContainer instanceof ContainerSchemaNode) { - reference = new DependencyAttribute(attrNode, - serviceInterfaceEntry, mandatory, - attrNode.getDescription()); - } else { - reference = new ListDependenciesAttribute(attrNode, - serviceInterfaceEntry, mandatory, - attrNode.getDescription()); - } - return Optional.of(reference); + public ModuleMXBeanEntryInitialBuilder setNamespace(String namespace) { + this.namespace = namespace; + return this; } - return Optional.absent(); - } - private static ServiceInterfaceEntry findSIE( - String prefixAndIdentityLocalName, Module currentModule, - Map qNamesToSIEs, - SchemaContext schemaContext) { - - Matcher m = PREFIX_COLON_LOCAL_NAME.matcher(prefixAndIdentityLocalName); - Module foundModule; - String localSIName; - if (m.matches()) { - // if there is a prefix, look for ModuleImport with this prefix. Get - // Module from SchemaContext - String prefix = m.group(1); - ModuleImport moduleImport = findModuleImport(currentModule, prefix); - foundModule = schemaContext.findModuleByName( - moduleImport.getModuleName(), moduleImport.getRevision()); - checkState( - foundModule != null, - format("Module not found in SchemaContext by %s", - moduleImport)); - localSIName = m.group(2); - } else { - foundModule = currentModule; // no prefix => SIE is in currentModule - localSIName = prefixAndIdentityLocalName; + public ModuleMXBeanEntryInitialBuilder setqName(QName qName) { + this.qName = qName; + return this; } - QName siQName = new QName(foundModule.getNamespace(), - foundModule.getRevision(), localSIName); - ServiceInterfaceEntry sie = qNamesToSIEs.get(siQName); - checkState(sie != null, "Cannot find referenced Service Interface by " - + prefixAndIdentityLocalName); - return sie; - } - private static ModuleImport findModuleImport(Module module, String prefix) { - for (ModuleImport moduleImport : module.getImports()) { - if (moduleImport.getPrefix().equals(prefix)) { - return moduleImport; - } + public ModuleMXBeanEntry.ModuleMXBeanEntryInitial build() { + return new ModuleMXBeanEntry.ModuleMXBeanEntryInitial(localName, description, packageName, javaNamePrefix, namespace, qName); } - throw new IllegalStateException(format( - "Import not found with prefix %s in %s", prefix, module)); - } - public Map getAttributes() { - return yangToAttributes; - } - - private void setYangToAttributes(Map newAttributes) { - this.yangToAttributes = newAttributes; - - } - - public String getNullableDescription() { - return nullableDescription; - } - - public QName getYangModuleQName() { - return yangModuleQName; - } + public ModuleMXBeanEntryInitialBuilder setIdSchemaNode(IdentitySchemaNode idSchemaNode) { + this.localName = idSchemaNode.getQName().getLocalName(); + this.description = idSchemaNode.getDescription(); + return this; + } - @Override - public String toString() { - return "ModuleMXBeanEntry{" + "globallyUniqueName='" - + globallyUniqueName + '\'' + ", packageName='" + packageName - + '\'' + '}'; } } 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 new file mode 100644 index 0000000000..4a9d5512d3 --- /dev/null +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java @@ -0,0 +1,523 @@ +/* + * 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.yangjmxgenerator; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.collect.Collections2; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute; +import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.ModuleImport; +import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; +import org.opendaylight.yangtools.yang.model.api.UsesNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.google.common.base.Preconditions.checkState; +import static java.lang.String.format; +import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName; + +final class ModuleMXBeanEntryBuilder { + + private Module currentModule; + private Map qNamesToSIEs; + private SchemaContext schemaContext; + private TypeProviderWrapper typeProviderWrapper; + private String packageName; + + public ModuleMXBeanEntryBuilder setModule(Module module) { + this.currentModule = module; + return this; + } + + public ModuleMXBeanEntryBuilder setqNamesToSIEs(Map qNamesToSIEs) { + this.qNamesToSIEs = qNamesToSIEs; + return this; + } + + public ModuleMXBeanEntryBuilder setSchemaContext(SchemaContext schemaContext) { + this.schemaContext = schemaContext; + return this; + } + + public ModuleMXBeanEntryBuilder setTypeProviderWrapper(TypeProviderWrapper typeProviderWrapper) { + this.typeProviderWrapper = typeProviderWrapper; + return this; + } + + public ModuleMXBeanEntryBuilder setPackageName(String packageName) { + this.packageName = packageName; + return this; + } + + private static final Logger logger = LoggerFactory + .getLogger(ModuleMXBeanEntryBuilder.class); + + // TODO: the XPath should be parsed by code generator IMO + private static final String MAGIC_STRING = "MAGIC_STRING"; + private static final String MODULE_CONDITION_XPATH_TEMPLATE = "^/MAGIC_STRING:modules/MAGIC_STRING:module/MAGIC_STRING:type\\s*=\\s*['\"](.+)['\"]$"; + private static final SchemaPath expectedConfigurationAugmentationSchemaPath = new SchemaPath( + Arrays.asList(createConfigQName("modules"), + createConfigQName("module"), + createConfigQName("configuration")), true); + private static final SchemaPath expectedStateAugmentationSchemaPath = new SchemaPath( + Arrays.asList(createConfigQName("modules"), + createConfigQName("module"), createConfigQName("state")), + true); + private static final Pattern PREFIX_COLON_LOCAL_NAME = Pattern + .compile("^(.+):(.+)$"); + + + public Map build() { + logger.debug("Generating ModuleMXBeans of {} to package {}", + currentModule.getNamespace(), packageName); + + String configModulePrefix; + try { + configModulePrefix = getConfigModulePrefixFromImport(currentModule); + } catch (IllegalArgumentException e) { + // this currentModule does not import config currentModule + return Collections.emptyMap(); + } + + // get identities of base config:currentModule-type + Map moduleIdentities = getIdentityMap(); + + Map uniqueGeneratedClassesNames = new HashMap<>(); + + // each currentModule name should have an augmentation defined + Map unaugmentedModuleIdentities = new HashMap<>( + moduleIdentities); + + Map result = new HashMap<>(); + + for (AugmentationSchema augmentation : currentModule.getAugmentations()) { + Set childNodes = augmentation.getChildNodes(); + if (areAllChildrenChoiceCaseNodes(childNodes)) { + for (ChoiceCaseNode childCase : castChildNodesToChoiceCases(childNodes)) { + // TODO refactor, extract to standalone builder class + processChoiceCaseNode(result, uniqueGeneratedClassesNames, configModulePrefix, moduleIdentities, + unaugmentedModuleIdentities, augmentation, childCase); + } + } // skip if child nodes are not all cases + } + // clean up nulls + cleanUpNulls(result); + // check attributes name uniqueness + checkAttributeNamesUniqueness(uniqueGeneratedClassesNames, result); + checkUnaugumentedIdentities(unaugmentedModuleIdentities); + + logger.debug("Number of ModuleMXBeans to be generated: {}", result.size()); + + return result; + } + + private static void cleanUpNulls(Map result) { + for (Map.Entry entry : result.entrySet()) { + ModuleMXBeanEntry module = entry.getValue(); + if (module.getAttributes() == null) { + module.setYangToAttributes(Collections + . emptyMap()); + } else if (module.getRuntimeBeans() == null) { + module.setRuntimeBeans(Collections + . emptyList()); + } + } + } + + private static void checkUnaugumentedIdentities(Map unaugmentedModuleIdentities) { + if (unaugmentedModuleIdentities.size() > 0) { + logger.warn("Augmentation not found for all currentModule identities: {}", + unaugmentedModuleIdentities.keySet()); + } + } + + private static void checkAttributeNamesUniqueness(Map uniqueGeneratedClassesNames, Map result) { + for (Map.Entry entry : result.entrySet()) { + checkUniqueRuntimeBeanAttributesName(entry.getValue(), + uniqueGeneratedClassesNames); + } + } + + private Map getIdentityMap() { + Map moduleIdentities = Maps.newHashMap(); + + for (IdentitySchemaNode id : currentModule.getIdentities()) { + if (id.getBaseIdentity() != null + && ConfigConstants.MODULE_TYPE_Q_NAME.equals(id.getBaseIdentity().getQName())) { + String identityLocalName = id.getQName().getLocalName(); + if (moduleIdentities.containsKey(identityLocalName)) { + throw new IllegalStateException("Module name already defined in this currentModule: " + + identityLocalName); + } else { + moduleIdentities.put(identityLocalName, id); + logger.debug("Found identity {}", identityLocalName); + } + // validation check on unknown schema nodes + 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())) { + // 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 { + throw new IllegalStateException("Unexpected language extension " + unknownNode.getNodeType()); + } + } + } + } + + return moduleIdentities; + } + + private Collection castChildNodesToChoiceCases(Set childNodes) { + return Collections2.transform(childNodes, new Function() { + @Nullable + @Override + public ChoiceCaseNode apply(@Nullable DataSchemaNode input) { + return (ChoiceCaseNode) input; + } + }); + } + + private boolean areAllChildrenChoiceCaseNodes(Set childNodes) { + for (DataSchemaNode childNode : childNodes) { + if (childNode instanceof ChoiceCaseNode == false) + return false; + } + return true; + } + + private void processChoiceCaseNode(Map result, + Map uniqueGeneratedClassesNames, String configModulePrefix, + Map moduleIdentities, + Map unaugmentedModuleIdentities, AugmentationSchema augmentation, + DataSchemaNode when) { + + ChoiceCaseNode choiceCaseNode = (ChoiceCaseNode) when; + if (choiceCaseNode.getConstraints() == null || choiceCaseNode.getConstraints().getWhenCondition() == null) { + return; + } + RevisionAwareXPath xPath = choiceCaseNode.getConstraints().getWhenCondition(); + Matcher matcher = getWhenConditionMatcher(configModulePrefix, xPath); + if (matcher.matches() == false) { + return; + } + String moduleLocalNameFromXPath = matcher.group(1); + IdentitySchemaNode moduleIdentity = moduleIdentities.get(moduleLocalNameFromXPath); + unaugmentedModuleIdentities.remove(moduleLocalNameFromXPath); + checkState(moduleIdentity != null, "Cannot find identity " + moduleLocalNameFromXPath + + " matching augmentation " + augmentation); + Map providedServices = findProvidedServices(moduleIdentity, currentModule, qNamesToSIEs, + schemaContext); + + if (moduleIdentity == null) { + throw new IllegalStateException("Cannot find identity specified by augmentation xpath constraint: " + + moduleLocalNameFromXPath + " of " + augmentation); + } + String javaNamePrefix = TypeProviderWrapper.findJavaNamePrefix(moduleIdentity); + + Map yangToAttributes = null; + // runtime-data + Collection runtimeBeans = null; + + if (expectedConfigurationAugmentationSchemaPath.equals(augmentation.getTargetPath())) { + logger.debug("Parsing configuration of {}", moduleLocalNameFromXPath); + yangToAttributes = fillConfiguration(choiceCaseNode, currentModule, typeProviderWrapper, qNamesToSIEs, + schemaContext, packageName); + checkUniqueAttributesWithGeneratedClass(uniqueGeneratedClassesNames, when.getQName(), yangToAttributes); + } else if (expectedStateAugmentationSchemaPath.equals(augmentation.getTargetPath())) { + logger.debug("Parsing state of {}", moduleLocalNameFromXPath); + try { + runtimeBeans = fillRuntimeBeans(choiceCaseNode, currentModule, typeProviderWrapper, packageName, + moduleLocalNameFromXPath, javaNamePrefix); + } catch (NameConflictException e) { + throw new NameConflictException(e.getConflictingName(), when.getQName(), when.getQName()); + } + checkUniqueRuntimeBeansGeneratedClasses(uniqueGeneratedClassesNames, when, runtimeBeans); + Set runtimeBeanEntryValues = Sets.newHashSet(runtimeBeans); + for (RuntimeBeanEntry entry : runtimeBeanEntryValues) { + checkUniqueAttributesWithGeneratedClass(uniqueGeneratedClassesNames, when.getQName(), + entry.getYangPropertiesToTypesMap()); + } + + } else { + throw new IllegalArgumentException("Cannot parse augmentation " + augmentation); + } + if (result.containsKey(moduleLocalNameFromXPath)) { + // either fill runtimeBeans or yangToAttributes + ModuleMXBeanEntry moduleMXBeanEntry = result.get(moduleLocalNameFromXPath); + if (yangToAttributes != null && moduleMXBeanEntry.getAttributes() == null) { + moduleMXBeanEntry.setYangToAttributes(yangToAttributes); + } else if (runtimeBeans != null && moduleMXBeanEntry.getRuntimeBeans() == null) { + moduleMXBeanEntry.setRuntimeBeans(runtimeBeans); + } + } else { + ModuleMXBeanEntry.ModuleMXBeanEntryInitial initial = new ModuleMXBeanEntry.ModuleMXBeanEntryInitialBuilder() + .setIdSchemaNode(moduleIdentity).setPackageName(packageName).setJavaNamePrefix(javaNamePrefix) + .setNamespace(currentModule.getNamespace().toString()).setqName(ModuleUtil.getQName(currentModule)) + .build(); + + // construct ModuleMXBeanEntry + ModuleMXBeanEntry moduleMXBeanEntry = new ModuleMXBeanEntry(initial, yangToAttributes, providedServices, + runtimeBeans); + + moduleMXBeanEntry.setYangModuleName(currentModule.getName()); + moduleMXBeanEntry.setYangModuleLocalname(moduleLocalNameFromXPath); + result.put(moduleLocalNameFromXPath, moduleMXBeanEntry); + } + } + + private void checkUniqueRuntimeBeansGeneratedClasses(Map uniqueGeneratedClassesNames, + DataSchemaNode when, Collection runtimeBeans) { + for (RuntimeBeanEntry runtimeBean : runtimeBeans) { + final String javaNameOfRuntimeMXBean = runtimeBean.getJavaNameOfRuntimeMXBean(); + if (uniqueGeneratedClassesNames.containsKey(javaNameOfRuntimeMXBean)) { + QName firstDefinedQName = uniqueGeneratedClassesNames.get(javaNameOfRuntimeMXBean); + throw new NameConflictException(javaNameOfRuntimeMXBean, firstDefinedQName, when.getQName()); + } + uniqueGeneratedClassesNames.put(javaNameOfRuntimeMXBean, when.getQName()); + } + } + + private static void checkUniqueRuntimeBeanAttributesName(ModuleMXBeanEntry mxBeanEntry, + Map uniqueGeneratedClassesNames) { + for (RuntimeBeanEntry runtimeBeanEntry : mxBeanEntry.getRuntimeBeans()) { + for (String runtimeAttName : runtimeBeanEntry.getYangPropertiesToTypesMap().keySet()) { + if (mxBeanEntry.getAttributes().keySet().contains(runtimeAttName)) { + QName qName1 = uniqueGeneratedClassesNames.get(runtimeBeanEntry.getJavaNameOfRuntimeMXBean()); + QName qName2 = uniqueGeneratedClassesNames.get(mxBeanEntry.getGloballyUniqueName()); + throw new NameConflictException(runtimeAttName, qName1, qName2); + } + } + } + } + + private void checkUniqueAttributesWithGeneratedClass(Map uniqueGeneratedClassNames, + QName parentQName, Map yangToAttributes) { + for (Map.Entry attr : yangToAttributes.entrySet()) { + if (attr.getValue() instanceof TOAttribute) { + checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName, (TOAttribute) attr.getValue()); + } else if (attr.getValue() instanceof ListAttribute + && ((ListAttribute) attr.getValue()).getInnerAttribute() instanceof TOAttribute) { + checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName, + (TOAttribute) ((ListAttribute) attr.getValue()).getInnerAttribute()); + } + } + } + + private void checkUniqueTOAttr(Map uniqueGeneratedClassNames, QName parentQName, TOAttribute attr) { + final String upperCaseCammelCase = attr.getUpperCaseCammelCase(); + if (uniqueGeneratedClassNames.containsKey(upperCaseCammelCase)) { + QName firstDefinedQName = uniqueGeneratedClassNames.get(upperCaseCammelCase); + throw new NameConflictException(upperCaseCammelCase, firstDefinedQName, parentQName); + } else { + uniqueGeneratedClassNames.put(upperCaseCammelCase, parentQName); + } + } + + private Collection fillRuntimeBeans(ChoiceCaseNode choiceCaseNode, Module currentModule, + TypeProviderWrapper typeProviderWrapper, String packageName, String moduleLocalNameFromXPath, + String javaNamePrefix) { + + return RuntimeBeanEntry.extractClassNameToRuntimeBeanMap(packageName, choiceCaseNode, moduleLocalNameFromXPath, + typeProviderWrapper, javaNamePrefix, currentModule).values(); + + } + + private Map fillConfiguration(ChoiceCaseNode choiceCaseNode, Module currentModule, + TypeProviderWrapper typeProviderWrapper, Map qNamesToSIEs, + SchemaContext schemaContext, String packageName) { + Map yangToAttributes = new HashMap<>(); + for (DataSchemaNode attrNode : choiceCaseNode.getChildNodes()) { + AttributeIfc attributeValue = getAttributeValue(attrNode, currentModule, qNamesToSIEs, typeProviderWrapper, + schemaContext, packageName); + yangToAttributes.put(attributeValue.getAttributeYangName(), attributeValue); + } + return yangToAttributes; + } + + private Map findProvidedServices(IdentitySchemaNode moduleIdentity, Module currentModule, + Map qNamesToSIEs, SchemaContext schemaContext) { + Map result = new HashMap<>(); + for (UnknownSchemaNode unknownNode : moduleIdentity.getUnknownSchemaNodes()) { + if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME.equals(unknownNode.getNodeType())) { + String prefixAndIdentityLocalName = unknownNode.getNodeParameter(); + ServiceInterfaceEntry sie = findSIE(prefixAndIdentityLocalName, currentModule, qNamesToSIEs, + schemaContext); + result.put(sie.getFullyQualifiedName(), sie.getQName()); + } + } + return result; + } + + private AttributeIfc getAttributeValue(DataSchemaNode attrNode, Module currentModule, + Map qNamesToSIEs, TypeProviderWrapper typeProviderWrapper, + SchemaContext schemaContext, String packageName) { + + if (attrNode instanceof LeafSchemaNode) { + // simple type + LeafSchemaNode leaf = (LeafSchemaNode) attrNode; + return new JavaAttribute(leaf, typeProviderWrapper); + } else if (attrNode instanceof ContainerSchemaNode) { + // reference or TO + ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) attrNode; + Optional dependencyAttributeOptional = extractDependency( + containerSchemaNode, attrNode, currentModule, qNamesToSIEs, schemaContext); + if (dependencyAttributeOptional.isPresent()) { + return dependencyAttributeOptional.get(); + } else { + return TOAttribute.create(containerSchemaNode, typeProviderWrapper, packageName); + } + + } else if (attrNode instanceof LeafListSchemaNode) { + return ListAttribute.create((LeafListSchemaNode) attrNode, typeProviderWrapper); + } else if (attrNode instanceof ListSchemaNode) { + ListSchemaNode listSchemaNode = (ListSchemaNode) attrNode; + Optional dependencyAttributeOptional = extractDependency( + listSchemaNode, attrNode, currentModule, qNamesToSIEs, schemaContext); + if (dependencyAttributeOptional.isPresent()) { + return dependencyAttributeOptional.get(); + } else { + return ListAttribute.create(listSchemaNode, typeProviderWrapper, packageName); + } + } else { + throw new UnsupportedOperationException("Unknown configuration node " + attrNode.toString()); + } + } + + private Optional extractDependency(DataNodeContainer dataNodeContainer, + DataSchemaNode attrNode, Module currentModule, Map qNamesToSIEs, + SchemaContext schemaContext) { + if (dataNodeContainer.getUses().size() == 1 && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) { + // reference + UsesNode usesNode = dataNodeContainer.getUses().iterator().next(); + checkState(usesNode.getRefines().size() == 1, "Unexpected 'refine' child node size of " + dataNodeContainer); + LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines().values().iterator().next(); + checkState(refine.getUnknownSchemaNodes().size() == 1, "Unexpected unknown schema node size of " + refine); + UnknownSchemaNode requiredIdentity = refine.getUnknownSchemaNodes().iterator().next(); + checkState(ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity.getNodeType()), + "Unexpected language extension " + requiredIdentity); + String prefixAndIdentityLocalName = requiredIdentity.getNodeParameter(); + // import should point to a module + ServiceInterfaceEntry serviceInterfaceEntry = findSIE(prefixAndIdentityLocalName, currentModule, + qNamesToSIEs, schemaContext); + boolean mandatory = refine.getConstraints().isMandatory(); + AbstractDependencyAttribute reference; + if (dataNodeContainer instanceof ContainerSchemaNode) { + reference = new DependencyAttribute(attrNode, serviceInterfaceEntry, mandatory, + attrNode.getDescription()); + } else { + reference = new ListDependenciesAttribute(attrNode, serviceInterfaceEntry, mandatory, + attrNode.getDescription()); + } + return Optional.of(reference); + } + return Optional.absent(); + } + + private int getChildNodeSizeWithoutUses(DataNodeContainer csn) { + int result = 0; + for (DataSchemaNode dsn : csn.getChildNodes()) { + if (dsn.isAddedByUses() == false) { + result++; + } + } + return result; + } + + private ServiceInterfaceEntry findSIE(String prefixAndIdentityLocalName, Module currentModule, + Map qNamesToSIEs, SchemaContext schemaContext) { + + Matcher m = PREFIX_COLON_LOCAL_NAME.matcher(prefixAndIdentityLocalName); + Module foundModule; + String localSIName; + if (m.matches()) { + // if there is a prefix, look for ModuleImport with this prefix. Get + // Module from SchemaContext + String prefix = m.group(1); + ModuleImport moduleImport = findModuleImport(currentModule, prefix); + foundModule = schemaContext.findModuleByName(moduleImport.getModuleName(), moduleImport.getRevision()); + checkState(foundModule != null, format("Module not found in SchemaContext by %s", moduleImport)); + localSIName = m.group(2); + } else { + foundModule = currentModule; // no prefix => SIE is in currentModule + localSIName = prefixAndIdentityLocalName; + } + QName siQName = new QName(foundModule.getNamespace(), foundModule.getRevision(), localSIName); + ServiceInterfaceEntry sie = qNamesToSIEs.get(siQName); + checkState(sie != null, "Cannot find referenced Service Interface by " + prefixAndIdentityLocalName); + return sie; + } + + private ModuleImport findModuleImport(Module module, String prefix) { + for (ModuleImport moduleImport : module.getImports()) { + if (moduleImport.getPrefix().equals(prefix)) { + return moduleImport; + } + } + throw new IllegalStateException(format("Import not found with prefix %s in %s", prefix, module)); + } + + @VisibleForTesting + static Matcher getWhenConditionMatcher(String prefix, RevisionAwareXPath whenConstraint) { + String xpathRegex = MODULE_CONDITION_XPATH_TEMPLATE.replace(MAGIC_STRING, prefix); + Pattern pattern = Pattern.compile(xpathRegex); + return pattern.matcher(whenConstraint.toString()); + } + + String getConfigModulePrefixFromImport(Module currentModule) { + for (ModuleImport currentImport : currentModule.getImports()) { + if (currentImport.getModuleName().equals(ConfigConstants.CONFIG_MODULE)) { + return currentImport.getPrefix(); + } + } + throw new IllegalArgumentException("Cannot find import " + ConfigConstants.CONFIG_MODULE + " in " + + currentModule); + } + +} diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java index 4831545b39..cd14458b0f 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java @@ -272,7 +272,7 @@ public class RuntimeBeanEntry { } // convert RpcDefinition to Rpc for (RpcDefinition rpcDefinition : rpcDefinitions) { - String name = ModuleMXBeanEntry + String name = TypeProviderWrapper .findJavaParameter(rpcDefinition); AttributeIfc returnType; if (rpcDefinition.getOutput() == null @@ -376,7 +376,7 @@ public class RuntimeBeanEntry { "More than one key is not supported in " + listSchemaNode); } - String javaNamePrefix = ModuleMXBeanEntry + String javaNamePrefix = TypeProviderWrapper .findJavaNamePrefix(listSchemaNode); RuntimeBeanEntry rbFromAttributes = new RuntimeBeanEntry(packageName, diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java index c43fead0fc..3c8c8aa2f4 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java @@ -7,12 +7,14 @@ */ package org.opendaylight.controller.config.yangjmxgenerator; +import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil; import org.opendaylight.yangtools.sal.binding.generator.spi.TypeProvider; import org.opendaylight.yangtools.sal.binding.model.api.Type; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; public class TypeProviderWrapper { private final TypeProvider typeProvider; @@ -21,6 +23,40 @@ public class TypeProviderWrapper { this.typeProvider = typeProvider; } + /** + * For input node, find if it contains config:java-name-prefix extension. If + * not found, convert local name of node converted to cammel case. + */ + public static String findJavaNamePrefix(SchemaNode schemaNode) { + return convertToJavaName(schemaNode, true); + } + + public static String findJavaParameter(SchemaNode schemaNode) { + return convertToJavaName(schemaNode, false); + } + + public static String convertToJavaName(SchemaNode schemaNode, + boolean capitalizeFirstLetter) { + for (UnknownSchemaNode unknownNode : schemaNode.getUnknownSchemaNodes()) { + if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME + .equals(unknownNode.getNodeType())) { + String value = unknownNode.getNodeParameter(); + return convertToJavaName(value, capitalizeFirstLetter); + } + } + return convertToJavaName(schemaNode.getQName().getLocalName(), + capitalizeFirstLetter); + } + + public static String convertToJavaName(String localName, + boolean capitalizeFirstLetter) { + if (capitalizeFirstLetter) { + return BindingGeneratorUtil.parseToClassName(localName); + } else { + return BindingGeneratorUtil.parseToValidParamName(localName); + } + } + public Type getType(LeafSchemaNode leaf) { TypeDefinition type = leaf.getType(); return getType(leaf, type); diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractAttribute.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractAttribute.java index ba2edc4e31..edfb4c59af 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractAttribute.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractAttribute.java @@ -7,7 +7,7 @@ */ package org.opendaylight.controller.config.yangjmxgenerator.attribute; -import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry; +import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; public abstract class AbstractAttribute implements AttributeIfc { @@ -22,8 +22,8 @@ public abstract class AbstractAttribute implements AttributeIfc { AbstractAttribute(DataSchemaNode attrNode) { this.attributeYangName = getLocalName(attrNode); this.node = attrNode; - this.upperCaseCammelCase = ModuleMXBeanEntry.findJavaNamePrefix(node); - this.lowerCaseCammelCase = ModuleMXBeanEntry.findJavaParameter(node); + this.upperCaseCammelCase = TypeProviderWrapper.findJavaNamePrefix(node); + this.lowerCaseCammelCase = TypeProviderWrapper.findJavaParameter(node); } @Override 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 6a540b50b2..84300cb81d 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 @@ -11,7 +11,6 @@ import com.google.common.base.Function; import com.google.common.collect.Collections2; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry; import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper; import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl; import org.opendaylight.yangtools.sal.binding.model.api.Type; @@ -121,7 +120,7 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute { .entrySet()) { capitalizedPropertiesToTypesMap.put( - ModuleMXBeanEntry.convertToJavaName(entry.getKey(), true), + TypeProviderWrapper.convertToJavaName(entry.getKey(), true), entry.getValue()); } return capitalizedPropertiesToTypesMap; @@ -133,7 +132,7 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute { .entrySet()) { jmxPropertiesToTypesMap.put( - ModuleMXBeanEntry.convertToJavaName(entry.getKey(), false), + TypeProviderWrapper.convertToJavaName(entry.getKey(), false), entry.getValue()); } return jmxPropertiesToTypesMap; diff --git a/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryTest.java b/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryTest.java index 9ea34ca2b8..8ca2bb5bc9 100644 --- a/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryTest.java +++ b/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryTest.java @@ -113,6 +113,9 @@ public class ModuleMXBeanEntryTest extends AbstractYangTest { , PACKAGE_NAME); Map attributes = namesToMBEs.get("impl-netconf") .getAttributes(); + + assertCorrectAttributesSize(namesToMBEs, attributes); + // DependencyAttribute threadFactoryAttribute = (DependencyAttribute) attributes .get("thread-factory"); @@ -132,6 +135,16 @@ public class ModuleMXBeanEntryTest extends AbstractYangTest { assertThat(threadFactoryAttribute.getType().getName(), is("ObjectName")); } + private void assertCorrectAttributesSize(Map namesToMBEs, Map attributes) { + assertEquals(14, attributes.size()); + assertEquals(1, namesToMBEs.get("impl-netconf").getRuntimeBeans().size()); + assertEquals(2, namesToMBEs.get("impl-netconf").getRuntimeBeans().iterator().next().getAttributes().size()); + + assertEquals(4, namesToMBEs.get("impl").getAttributes().size()); + assertEquals(1, namesToMBEs.get("impl").getRuntimeBeans().size()); + assertEquals(1, namesToMBEs.get("impl").getRuntimeBeans().iterator().next().getAttributes().size()); + } + protected RuntimeBeanEntry findFirstByYangName( Collection runtimeBeans, String yangName) { for (RuntimeBeanEntry rb : runtimeBeans) { @@ -155,7 +168,7 @@ public class ModuleMXBeanEntryTest extends AbstractYangTest { private void assertMatches(String prefix, String input) { RevisionAwareXPath whenConstraint = mock(RevisionAwareXPath.class); doReturn(input).when(whenConstraint).toString(); - Matcher output = ModuleMXBeanEntry.getWhenConditionMatcher(prefix, + Matcher output = ModuleMXBeanEntryBuilder.getWhenConditionMatcher(prefix, whenConstraint); assertTrue(output.matches()); assertEquals("threadpool-dynamic", output.group(1)); diff --git a/opendaylight/config/yang-jmx-generator/src/test/resources/config-jmx-it-impl.yang b/opendaylight/config/yang-jmx-generator/src/test/resources/config-jmx-it-impl.yang index 97078e033a..16085efbba 100644 --- a/opendaylight/config/yang-jmx-generator/src/test/resources/config-jmx-it-impl.yang +++ b/opendaylight/config/yang-jmx-generator/src/test/resources/config-jmx-it-impl.yang @@ -8,8 +8,6 @@ module config-jmx-it-impl { import ietf-inet-types { prefix inet; revision-date 2010-09-24;} import config-threads { prefix th; revision-date 2013-04-09; } - - description "Testing IMPL"; @@ -67,19 +65,7 @@ module config-jmx-it-impl { } } - } - - augment "/config:modules/config:module/config:state" { - case impl { - when "/config:modules/config:module/config:type = 'impl'"; - // root runtime bean - leaf created-sessions { - type uint32; - } - } - } - augment "/config:modules/config:module/config:configuration" { case impl-netconf { when "/config:modules/config:module/config:type = 'impl-netconf'"; @@ -205,6 +191,14 @@ module config-jmx-it-impl { } augment "/config:modules/config:module/config:state" { + case impl { + when "/config:modules/config:module/config:type = 'impl'"; + // root runtime bean + leaf created-sessions { + type uint32; + } + } + case impl-netconf { when "/config:modules/config:module/config:type = 'impl-netconf'"; // root runtime bean @@ -212,6 +206,11 @@ module config-jmx-it-impl { type uint32; } + leaf created-sessions-2 { + type uint32; + } + } } + } diff --git a/opendaylight/config/yang-test/pom.xml b/opendaylight/config/yang-test/pom.xml index 9c6e98e571..9037ff0c0f 100644 --- a/opendaylight/config/yang-test/pom.xml +++ b/opendaylight/config/yang-test/pom.xml @@ -106,7 +106,6 @@ org.opendaylight.yangtools yang-maven-plugin - ${yangtools.version} config diff --git a/opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/IConfigurationContainerService.java b/opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/IConfigurationContainerService.java index 2123f6b9eb..ee571b83e1 100644 --- a/opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/IConfigurationContainerService.java +++ b/opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/IConfigurationContainerService.java @@ -13,4 +13,12 @@ package org.opendaylight.controller.configuration; * Container configuration service */ public interface IConfigurationContainerService extends IConfigurationServiceCommon { + + /** + * Bundle will call this function to ask ContainerConfigurationService to provide the + * directory location of container + * + * @return The path to active container directory + */ + String getConfigurationRoot(); } diff --git a/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ConfigurationService.java b/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ConfigurationService.java index e4d55d11fb..4c0f3a2da5 100644 --- a/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ConfigurationService.java +++ b/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ConfigurationService.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.configuration.internal; +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; @@ -25,6 +26,7 @@ import org.opendaylight.controller.clustering.services.IClusterServices; import org.opendaylight.controller.configuration.ConfigurationEvent; import org.opendaylight.controller.configuration.ConfigurationObject; import org.opendaylight.controller.configuration.IConfigurationAware; +import org.opendaylight.controller.configuration.IConfigurationContainerService; import org.opendaylight.controller.configuration.IConfigurationService; import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.sal.utils.IObjectReader; @@ -46,7 +48,7 @@ public class ConfigurationService implements IConfigurationService, ICacheUpdate private static final Logger logger = LoggerFactory .getLogger(ConfigurationService.class); public static final String SAVE_EVENT_CACHE = "config.event.save"; - private static final Object ROOT = GlobalConstants.STARTUPHOME.toString(); + private static final String ROOT = GlobalConstants.STARTUPHOME.toString(); private IClusterGlobalServices clusterServices; private ConcurrentMap configEvent; private Set configurationAwareList = Collections @@ -105,21 +107,66 @@ public class ConfigurationService implements IConfigurationService, ICacheUpdate return saveConfigurationsInternal(); } + + private List getContainerDirectoryList() { + List containerList = new ArrayList(); + for (IConfigurationAware configurationAware : this.configurationAwareList) { + if (configurationAware instanceof IConfigurationContainerService) { + String containerFilePath = ((ContainerConfigurationService)configurationAware).getConfigurationRoot(); + containerList.add(containerFilePath); + } + } + return containerList; + } + + private void createContainerDirectory(IConfigurationAware configurationAware) { + String containerFilePath = ((ContainerConfigurationService) configurationAware).getConfigurationRoot(); + if (!new File(containerFilePath).exists()) { + boolean created = new File(containerFilePath).mkdir(); + if (!created) { + logger.error("Failed to create startup config directory: {}", containerFilePath); + } + } + } + + private void clearStaleContainerDirectories() { + List activeContainers = getContainerDirectoryList(); + for (File file : new File(ROOT).listFiles()) { + if (file.isDirectory() && !activeContainers.contains(file.toPath() + File.separator)) { + logger.trace("Removing directory for container {}", file.getName()); + for (File innerFile : file.listFiles()) { + innerFile.delete(); + } + boolean removed = file.delete(); + if (!removed) { + logger.warn("Failed to remove stale directory: {}", file.getName()); + } + } + } + } + + private Status saveConfigurationsInternal() { boolean success = true; for (IConfigurationAware configurationAware : configurationAwareList) { + if (configurationAware instanceof IConfigurationContainerService) { + // Create directory for new containers + createContainerDirectory(configurationAware); + } Status status = configurationAware.saveConfiguration(); if (!status.isSuccess()) { success = false; - logger.warn("Failed to save config for {}", - configurationAware.getClass().getName()); + logger.warn("Failed to save config for {}", configurationAware.getClass().getName()); } } + // Remove startup directories of containers that were removed from + // the configuration but not saved + clearStaleContainerDirectories(); + if (success) { return new Status(StatusCode.SUCCESS); } else { - return new Status(StatusCode.INTERNALERROR, - "Failed to Save All Configurations"); + return new Status(StatusCode.INTERNALERROR, "Failed to Save All Configurations"); } } diff --git a/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ContainerConfigurationService.java b/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ContainerConfigurationService.java index 9c1d391daa..3e067254ed 100644 --- a/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ContainerConfigurationService.java +++ b/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ContainerConfigurationService.java @@ -9,7 +9,6 @@ package org.opendaylight.controller.configuration.internal; -import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Dictionary; @@ -52,14 +51,10 @@ public class ContainerConfigurationService implements IConfigurationContainerSer private static final Logger logger = LoggerFactory.getLogger(ContainerConfigurationService.class); private IClusterContainerServices clusterServices; private ConcurrentMap containerConfigEvent; - /* - * Collection containing the configuration objects. - * This is configuration world: container names (also the map key) - * are maintained as they were configured by user, same case - */ + // Directory which contains the startup files for this container + private String root; private Set configurationAwareList = Collections .synchronizedSet(new HashSet()); - private String root; private ObjectReader objReader; private ObjectWriter objWriter; @@ -93,14 +88,9 @@ public class ContainerConfigurationService implements IConfigurationContainerSer void init(Component c) { Dictionary props = c.getServiceProperties(); - String containerName = (props != null) ? (String) props.get("containerName") : GlobalConstants.DEFAULT.toString(); - root = String.format("%s%s/", GlobalConstants.STARTUPHOME.toString(), containerName); - if (!new File(root).exists()) { - boolean created = new File(root).mkdir(); - if (!created) { - logger.error("Failed to create startup config directory for container {}", containerName); - } - } + String containerName = (props != null) ? (String) props.get("containerName") : + GlobalConstants.DEFAULT.toString(); + root = String.format("%s%s/", GlobalConstants.STARTUPHOME.toString(), containerName); } public void start() { @@ -119,17 +109,18 @@ public class ContainerConfigurationService implements IConfigurationContainerSer * Function called by the dependency manager before Container is Stopped and Destroyed. */ public void containerStop() { - // Remove container directory along with its startup files - File[] files = new File(root).listFiles(); - for (File file : files) { - file.delete(); - } - new File(root).delete(); + // Do nothing + } + + @Override + public String getConfigurationRoot() { + return root; } @Override public Status saveConfiguration() { boolean success = true; + for (IConfigurationContainerAware configurationAware : configurationAwareList) { logger.trace("Save Config triggered for {}", configurationAware.getClass().getSimpleName()); diff --git a/opendaylight/connectionmanager/implementation/pom.xml b/opendaylight/connectionmanager/implementation/pom.xml index 7de43962cf..3bd7ea1386 100644 --- a/opendaylight/connectionmanager/implementation/pom.xml +++ b/opendaylight/connectionmanager/implementation/pom.xml @@ -54,22 +54,18 @@ org.opendaylight.controller clustering.services - 0.5.1-SNAPSHOT org.opendaylight.controller connectionmanager - 0.1.2-SNAPSHOT org.opendaylight.controller sal - 0.7.1-SNAPSHOT org.opendaylight.controller sal.connection - 0.1.2-SNAPSHOT equinoxSDK381 diff --git a/opendaylight/containermanager/implementation/src/main/java/org/opendaylight/controller/containermanager/internal/ContainerManager.java b/opendaylight/containermanager/implementation/src/main/java/org/opendaylight/controller/containermanager/internal/ContainerManager.java index ad897fd689..0fee183b67 100644 --- a/opendaylight/containermanager/implementation/src/main/java/org/opendaylight/controller/containermanager/internal/ContainerManager.java +++ b/opendaylight/containermanager/implementation/src/main/java/org/opendaylight/controller/containermanager/internal/ContainerManager.java @@ -9,7 +9,6 @@ package org.opendaylight.controller.containermanager.internal; -import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; @@ -751,26 +750,6 @@ public class ContainerManager extends Authorization implements IContaine return status; } - private void removeComponentsStartUpfiles(String containerName) { - String startupLocation = String.format("./%s", GlobalConstants.STARTUPHOME.toString()); - String containerPrint = String.format("_%s.", containerName.toLowerCase(Locale.ENGLISH)); - - File directory = new File(startupLocation); - String[] fileList = directory.list(); - - logger.trace("Deleting startup configuration files for container {}", containerName); - if (fileList != null) { - for (String fileName : fileList) { - if (fileName.contains(containerPrint)) { - String fullPath = String.format("%s/%s", startupLocation, fileName); - File file = new File(fullPath); - boolean done = file.delete(); - logger.trace("{} {}", (done ? "Deleted: " : "Failed to delete: "), fileName); - } - } - } - } - /** * Create and initialize default all resource group and create association * with default well known users and profiles, if not already learnt from @@ -1013,19 +992,6 @@ public class ContainerManager extends Authorization implements IContaine notifyContainerModeChange(delete, notifyLocal); // Notify listeners notifyContainerAwareListeners(container, delete); - - /* - * This is a quick fix until configuration service becomes the - * centralized configuration management place. Here container manager - * will remove the startup files for all the bundles that are present in - * the container being deleted. Do the cleanup here in Container manger - * as do not want to put this temporary code in Configuration manager - * yet which is ODL. - */ - if (delete) { - // TODO: remove when Config Mgr takes over - removeComponentsStartUpfiles(containerName); - } } private void notifyContainerEntryChangeInternal(String containerName, List ncList, UpdateType update, boolean notifyLocal) { diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 5aba5ca5cb..79b9ccea83 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -30,141 +30,123 @@ org.opendaylight.controller sal-common - ${mdsal.version} org.opendaylight.controller sal-common-util - ${mdsal.version} org.opendaylight.controller sal-netconf-connector - ${mdsal.version} org.opendaylight.controller sal-core-api - ${mdsal.version} org.opendaylight.controller sal-broker-impl - ${mdsal.version} + + + org.opendaylight.controller + sal-remote + + + org.opendaylight.controller + sal-restconf-broker org.opendaylight.controller sal-core-spi - ${mdsal.version} org.opendaylight.controller sal-common-api - ${mdsal.version} org.opendaylight.controller sal-common-impl - ${mdsal.version} org.opendaylight.controller sal-binding-api - ${mdsal.version} org.opendaylight.controller sal-binding-config - ${mdsal.version} org.opendaylight.controller sal-binding-broker-impl - ${mdsal.version} org.opendaylight.controller sal-compatibility - ${mdsal.version} org.opendaylight.controller sal-connector-api - ${mdsal.version} org.opendaylight.controller sal-rest-connector - ${mdsal.version} org.opendaylight.controller.model model-inventory - ${mdsal.version} org.opendaylight.controller.model model-flow-base - ${mdsal.version} org.opendaylight.controller.model model-flow-service - ${mdsal.version} org.opendaylight.controller.model model-flow-statistics - ${mdsal.version} org.opendaylight.controller.model model-flow-management - ${mdsal.version} org.opendaylight.controller.md inventory-manager - ${mdsal.version} org.opendaylight.controller.md forwardingrules-manager - ${mdsal.version} org.opendaylight.controller.md topology-lldp-discovery - ${mdsal.version} org.opendaylight.controller.md topology-manager - ${mdsal.version} - org.opendaylight.controller.model - model-topology - 1.1-SNAPSHOT + org.opendaylight.controller.model + model-topology + 1.1-SNAPSHOT org.opendaylight.yangtools.model ietf-topology - org.opendaylight.controller - sal-binding-util - 1.1-SNAPSHOT + org.opendaylight.controller + sal-binding-util org.opendaylight.controller.md statistics-manager - ${mdsal.version} org.opendaylight.controller concepts - ${concepts.version} org.opendaylight.controller @@ -173,137 +155,119 @@ org.opendaylight.yangtools concepts - ${yangtools.version} + + + org.opendaylight.yangtools + restconf-client-api + + + org.opendaylight.yangtools + restconf-client-impl org.opendaylight.controller config-api - ${config.version} org.opendaylight.controller config-manager - ${config.version} org.opendaylight.controller yang-jmx-generator - ${config.version} org.opendaylight.controller yang-store-api - ${config.version} org.opendaylight.controller yang-store-impl - ${config.version} org.opendaylight.controller logback-config - ${config.version} org.opendaylight.controller config-persister-api - ${config.version} org.opendaylight.controller config-persister-file-adapter - ${config.version} org.opendaylight.controller config-persister-file-xml-adapter - ${config.version} org.opendaylight.controller config-persister-directory-adapter - ${config.version} org.opendaylight.controller config-persister-directory-xml-adapter - ${config.version} org.opendaylight.controller config-persister-directory-autodetect-adapter - ${config.version} org.opendaylight.controller shutdown-api - ${config.version} org.opendaylight.controller shutdown-impl - ${config.version} org.opendaylight.controller netconf-api - ${netconf.version} org.opendaylight.controller netconf-impl - ${netconf.version} org.opendaylight.controller netconf-util - ${netconf.version} org.opendaylight.controller netconf-client - ${netconf.version} org.opendaylight.controller netconf-mapping-api - ${netconf.version} org.opendaylight.controller netconf-ssh - ${netconf.version} org.opendaylight.controller config-netconf-connector - ${netconf.version} org.opendaylight.controller netconf-monitoring - ${netconf.version} ${project.groupId} ietf-netconf-monitoring - ${netconf.version} ${project.groupId} ietf-netconf-monitoring-extension - ${netconf.version} org.opendaylight.controller config-persister-impl - ${netconf.version} org.apache.servicemix.bundles @@ -320,35 +284,28 @@ org.opendaylight.controller threadpool-config-api - ${config.version} org.opendaylight.controller netty-config-api - ${config.version} org.opendaylight.controller threadpool-config-impl - ${config.version} org.opendaylight.controller netty-threadgroup-config - ${config.version} org.opendaylight.controller netty-event-executor-config - ${config.version} org.opendaylight.controller netty-timer-config - ${config.version} - org.opendaylight.controller.samples @@ -369,7 +326,6 @@ org.opendaylight.yangtools yang-binding - ${yangtools.version} org.opendaylight.yangtools @@ -425,7 +381,6 @@ org.opendaylight.yangtools yang-model-util - ${yangtools.version} org.opendaylight.yangtools diff --git a/opendaylight/forwardingrulesmanager/implementation/pom.xml b/opendaylight/forwardingrulesmanager/implementation/pom.xml index 8db8a0b8fd..f7bbdc14aa 100644 --- a/opendaylight/forwardingrulesmanager/implementation/pom.xml +++ b/opendaylight/forwardingrulesmanager/implementation/pom.xml @@ -72,12 +72,10 @@ org.opendaylight.controller configuration - 0.4.2-SNAPSHOT org.opendaylight.controller clustering.services - 0.5.1-SNAPSHOT org.opendaylight.controller @@ -86,17 +84,14 @@ org.opendaylight.controller sal - 0.7.1-SNAPSHOT org.opendaylight.controller sal.connection - 0.1.2-SNAPSHOT org.opendaylight.controller forwardingrulesmanager - 0.5.1-SNAPSHOT equinoxSDK381 @@ -105,12 +100,10 @@ org.opendaylight.controller connectionmanager - 0.1.2-SNAPSHOT org.opendaylight.controller containermanager - 0.5.2-SNAPSHOT diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/pom.xml b/opendaylight/md-sal/compatibility/flow-management-compatibility/pom.xml index 41db8af590..fc0ef32954 100644 --- a/opendaylight/md-sal/compatibility/flow-management-compatibility/pom.xml +++ b/opendaylight/md-sal/compatibility/flow-management-compatibility/pom.xml @@ -40,12 +40,10 @@ org.opendaylight.controller sal-common-util - 1.1-SNAPSHOT org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT org.slf4j @@ -72,17 +70,14 @@ org.opendaylight.controller.model model-flow-management - 1.1-SNAPSHOT org.opendaylight.controller forwardingrulesmanager - 0.5.1-SNAPSHOT org.opendaylight.controller sal-compatibility - 1.1-SNAPSHOT diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml index 46f1c4f57b..b7e193b59d 100644 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml @@ -41,22 +41,18 @@ org.opendaylight.controller sal-common-util - 1.1-SNAPSHOT org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT org.opendaylight.controller switchmanager - 0.7.1-SNAPSHOT org.opendaylight.controller topologymanager - 0.4.2-SNAPSHOT org.slf4j @@ -83,12 +79,10 @@ org.opendaylight.controller.model model-flow-management - 1.1-SNAPSHOT org.opendaylight.controller sal-binding-util - 1.1-SNAPSHOT org.opendaylight.controller.model @@ -98,12 +92,10 @@ org.opendaylight.controller forwardingrulesmanager - 0.5.1-SNAPSHOT org.opendaylight.controller sal-compatibility - 1.1-SNAPSHOT diff --git a/opendaylight/md-sal/compatibility/pom.xml b/opendaylight/md-sal/compatibility/pom.xml index 606cf212e5..c5c5cd32c5 100644 --- a/opendaylight/md-sal/compatibility/pom.xml +++ b/opendaylight/md-sal/compatibility/pom.xml @@ -25,22 +25,18 @@ org.opendaylight.controller sal - 0.7.1-SNAPSHOT org.opendaylight.controller.model model-flow-service - 1.1-SNAPSHOT org.opendaylight.controller sal-common-util - 1.1-SNAPSHOT org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT com.google.guava diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml b/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml index daef08949a..6914ef3c43 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml +++ b/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml @@ -18,7 +18,6 @@ org.opendaylight.controller.model model-flow-statistics - 1.1-SNAPSHOT org.opendaylight.controller.model @@ -28,12 +27,10 @@ org.opendaylight.controller sal-binding-util - 1.1-SNAPSHOT org.opendaylight.controller clustering.services - 0.5.1-SNAPSHOT bundle diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend index a6fc4b0a23..a59c2c1636 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend @@ -251,6 +251,7 @@ package class SalCompatibilityProvider implements BindingAwareProvider { topology.dataService = session.getSALService(DataProviderService) tpProvider.dataService = session.getSALService(DataProviderService) + inventory.start(); tpProvider.start(); diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend index fac12ee10d..8a0874ee31 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend @@ -199,9 +199,11 @@ class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowLi } private def Future> internalModifyFlowAsync(Node node, Flow oldFlow, Flow newFlow, long rid) { - val flowId = getCache().remove(oldFlow); + var flowId = getCache().remove(oldFlow); if(flowId == null){ - throw new IllegalArgumentException("oldFlow is unknown"); + LOG.error("oldFlow not found in cache : " + oldFlow.hashCode); + flowId = UUID.randomUUID(); + getCache().put(oldFlow, flowId); } getCache().put(newFlow, flowId); @@ -212,7 +214,9 @@ class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowLi private def Future> internalRemoveFlowAsync(Node node, Flow adflow, long rid){ val flowId = getCache().remove(adflow); if(flowId == null){ - throw new IllegalArgumentException("adflow is unknown"); + //throw new IllegalArgumentException("adflow not found in cache : " + adflow.hashCode); + LOG.error("adflow not found in cache : " + adflow.hashCode); + return null; } val flow = adflow.toMDFlow(flowId.toString()); val modification = this._dataBrokerService.beginTransaction(); @@ -227,6 +231,10 @@ class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowLi } private def toFutureStatus(Future> future){ + if(future == null){ + return toStatus(true); + } + try { val result = future.get(); return toStatus(result); diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend index 60e43247c2..0c211fd0aa 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend @@ -11,6 +11,9 @@ import java.util.ArrayList import java.util.Collections import java.util.List import java.util.Set +import java.util.ArrayList; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.Lock; import java.util.concurrent.CopyOnWriteArrayList; import org.opendaylight.controller.sal.binding.api.data.DataBrokerService import org.opendaylight.controller.sal.binding.api.data.DataProviderService @@ -76,17 +79,18 @@ import static extension org.opendaylight.controller.sal.compatibility.NodeMappin import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader import java.util.concurrent.ConcurrentHashMap import java.util.Map +import java.util.HashMap class InventoryAndReadAdapter implements IPluginInReadService, - IPluginInInventoryService, - OpendaylightInventoryListener, - OpendaylightFlowStatisticsListener, - OpendaylightFlowTableStatisticsListener, - OpendaylightPortStatisticsListener { + IPluginInInventoryService, + OpendaylightInventoryListener, + OpendaylightFlowStatisticsListener, + OpendaylightFlowTableStatisticsListener, + OpendaylightPortStatisticsListener { private static val LOG = LoggerFactory.getLogger(InventoryAndReadAdapter); - private static val OPENFLOWV10_TABLE_ID = new Integer(0).shortValue; + private static val OPENFLOWV10_TABLE_ID = new Integer(0).shortValue; @Property DataBrokerService dataService; @@ -111,21 +115,34 @@ class InventoryAndReadAdapter implements IPluginInReadService, @Property List inventoryPublisher = new CopyOnWriteArrayList(); - def setInventoryPublisher(IPluginOutInventoryService listener){ + private final InventoryNotificationProvider inventoryNotificationProvider = new InventoryNotificationProvider(); + + private final Map> nodeToNodeConnectorsMap = new ConcurrentHashMap>(); + + private final Lock nodeToNodeConnectorsLock = new ReentrantLock(); + + + def start(){ + inventoryNotificationProvider.dataProviderService = dataProviderService; + inventoryNotificationProvider.inventoryPublisher = inventoryPublisher; + // inventoryNotificationProvider.start(); + } + + def setInventoryPublisher(IPluginOutInventoryService listener){ inventoryPublisher.add(listener); - } + } - def unsetInventoryPublisher(IPluginOutInventoryService listener){ + def unsetInventoryPublisher(IPluginOutInventoryService listener){ inventoryPublisher.remove(listener); - } + } def setReadPublisher(IPluginOutReadService listener) { - statisticsPublisher.add(listener); + statisticsPublisher.add(listener); } def unsetReadPublisher (IPluginOutReadService listener) { - if( listener != null) - statisticsPublisher.remove(listener); + if( listener != null) + statisticsPublisher.remove(listener); } protected def startChange() { @@ -140,33 +157,33 @@ class InventoryAndReadAdapter implements IPluginInReadService, override readAllFlow(Node node, boolean cached) { val output = new ArrayList(); - val tableRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) - .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance(); - - val it = this.startChange(); - - val table= it.readConfigurationData(tableRef) as Table; - - if(table != null){ - LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size); - - for(flow : table.flow){ - - val adsalFlow = ToSalConversionsUtils.toFlow(flow,node); - val statsFromDataStore = flow.getAugmentation(FlowStatisticsData); - - if(statsFromDataStore != null){ - val it = new FlowOnNode(adsalFlow); - byteCount = statsFromDataStore.flowStatistics.byteCount.value.longValue; - packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue; - durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue; - durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue; - - output.add(it); - } - } - } + val tableRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) + .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance(); + + val it = this.startChange(); + + val table= it.readConfigurationData(tableRef) as Table; + + if(table != null){ + LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size); + + for(flow : table.flow){ + + val adsalFlow = ToSalConversionsUtils.toFlow(flow,node); + val statsFromDataStore = flow.getAugmentation(FlowStatisticsData); + + if(statsFromDataStore != null){ + val it = new FlowOnNode(adsalFlow); + byteCount = statsFromDataStore.flowStatistics.byteCount.value.longValue; + packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue; + durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue; + durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue; + + output.add(it); + } + } + } //TODO (main): Shell we send request to the switch? It will make async request to the switch. // Once plugin receive response, it will let adaptor know through onFlowStatisticsUpdate() @@ -180,35 +197,35 @@ class InventoryAndReadAdapter implements IPluginInReadService, } override readAllNodeConnector(Node node, boolean cached) { - - val ret = new ArrayList(); - val nodeRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) - .toInstance(); - - val provider = this.startChange(); - - val dsNode= provider.readConfigurationData(nodeRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; - - if(dsNode != null){ - - for (dsNodeConnector : dsNode.nodeConnector){ - val nodeConnectorRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) - .child(NodeConnector, dsNodeConnector.key) - .toInstance(); - - val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector; - - if(nodeConnectorFromDS != null){ - val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics; - - ret.add(toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,dsNode.id,dsNodeConnector.id)); - } - } - } - - //TODO: Refer TODO (main) + + val ret = new ArrayList(); + val nodeRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) + .toInstance(); + + val provider = this.startChange(); + + val dsNode= provider.readConfigurationData(nodeRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; + + if(dsNode != null){ + + for (dsNodeConnector : dsNode.nodeConnector){ + val nodeConnectorRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) + .child(NodeConnector, dsNodeConnector.key) + .toInstance(); + + val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector; + + if(nodeConnectorFromDS != null){ + val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics; + + ret.add(toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,dsNode.id,dsNodeConnector.id)); + } + } + } + + //TODO: Refer TODO (main) val input = new GetAllNodeConnectorsStatisticsInputBuilder(); input.setNode(node.toNodeRef); nodeConnectorStatisticsService.getAllNodeConnectorsStatistics(input.build()); @@ -216,23 +233,23 @@ class InventoryAndReadAdapter implements IPluginInReadService, } override readAllNodeTable(Node node, boolean cached) { - val ret = new ArrayList(); - - val dsFlowCapableNode= readFlowCapableNode(node.toNodeRef) - - if(dsFlowCapableNode != null){ - - for (table : dsFlowCapableNode.table){ - - val tableStats = table.getAugmentation(FlowTableStatisticsData); - - if(tableStats != null){ - ret.add(toNodeTableStatistics(tableStats.flowTableStatistics,table.id,node)); - } - } - } - - //TODO: Refer TODO (main) + val ret = new ArrayList(); + + val dsFlowCapableNode= readFlowCapableNode(node.toNodeRef) + + if(dsFlowCapableNode != null){ + + for (table : dsFlowCapableNode.table){ + + val tableStats = table.getAugmentation(FlowTableStatisticsData); + + if(tableStats != null){ + ret.add(toNodeTableStatistics(tableStats.flowTableStatistics,table.id,node)); + } + } + } + + //TODO: Refer TODO (main) val input = new GetFlowTablesStatisticsInputBuilder(); input.setNode(node.toNodeRef); flowTableStatisticsService.getFlowTablesStatistics(input.build); @@ -241,39 +258,39 @@ class InventoryAndReadAdapter implements IPluginInReadService, override readDescription(Node node, boolean cached) { return toNodeDescription(node.toNodeRef); - } + } override readFlow(Node node, Flow targetFlow, boolean cached) { - var FlowOnNode ret= null; - - val tableRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) - .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance(); - - val it = this.startChange(); - - val table= it.readConfigurationData(tableRef) as Table; - - if(table != null){ - LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size); - - for(mdsalFlow : table.flow){ - if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))){ - val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData); - - if(statsFromDataStore != null){ - LOG.debug("Found matching flow in the data store flow table "); - val it = new FlowOnNode(targetFlow); - byteCount = statsFromDataStore.flowStatistics.byteCount.value.longValue; - packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue; - durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue; - durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue; - - ret = it; - } - } - } - } + var FlowOnNode ret= null; + + val tableRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) + .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance(); + + val it = this.startChange(); + + val table= it.readConfigurationData(tableRef) as Table; + + if(table != null){ + LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size); + + for(mdsalFlow : table.flow){ + if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))){ + val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData); + + if(statsFromDataStore != null){ + LOG.debug("Found matching flow in the data store flow table "); + val it = new FlowOnNode(targetFlow); + byteCount = statsFromDataStore.flowStatistics.byteCount.value.longValue; + packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue; + durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue; + durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue; + + ret = it; + } + } + } + } //TODO: Refer TODO (main) val input = new GetFlowStatisticsFromFlowTableInputBuilder; @@ -282,30 +299,30 @@ class InventoryAndReadAdapter implements IPluginInReadService, flowStatisticsService.getFlowStatisticsFromFlowTable(input.build) return ret; - + } override readNodeConnector(org.opendaylight.controller.sal.core.NodeConnector connector, boolean cached) { - var NodeConnectorStatistics nodeConnectorStatistics = null; - - val nodeConnectorRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(connector.node)) - .child(NodeConnector, InventoryMapping.toNodeConnectorKey(connector)) - .toInstance(); - val provider = this.startChange(); - - val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector; - - if(nodeConnectorFromDS != null){ - val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics; - if(nodeConnectorStatsFromDs != null) { - nodeConnectorStatistics = toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics, - InventoryMapping.toNodeKey(connector.node).id, - InventoryMapping.toNodeConnectorKey(connector).id); - } - } - - //TODO: Refer TODO (main) + var NodeConnectorStatistics nodeConnectorStatistics = null; + + val nodeConnectorRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(connector.node)) + .child(NodeConnector, InventoryMapping.toNodeConnectorKey(connector)) + .toInstance(); + val provider = this.startChange(); + + val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector; + + if(nodeConnectorFromDS != null){ + val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics; + if(nodeConnectorStatsFromDs != null) { + nodeConnectorStatistics = toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics, + InventoryMapping.toNodeKey(connector.node).id, + InventoryMapping.toNodeConnectorKey(connector).id); + } + } + + //TODO: Refer TODO (main) val input = new GetNodeConnectorStatisticsInputBuilder(); input.setNode(connector.node.toNodeRef); input.setNodeConnectorId(InventoryMapping.toNodeConnectorKey(connector).id); @@ -314,25 +331,25 @@ class InventoryAndReadAdapter implements IPluginInReadService, } override readNodeTable(NodeTable nodeTable, boolean cached) { - var NodeTableStatistics nodeStats = null - - val tableRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(nodeTable.node)) - .augmentation(FlowCapableNode).child(Table, new TableKey(nodeTable.ID as Short)).toInstance(); - - val it = this.startChange(); - - val table= it.readConfigurationData(tableRef) as Table; - - if(table != null){ - val tableStats = table.getAugmentation(FlowTableStatisticsData); - - if(tableStats != null){ - nodeStats = toNodeTableStatistics(tableStats.flowTableStatistics,table.id,nodeTable.node); - } - } - - //TODO: Refer TODO (main) + var NodeTableStatistics nodeStats = null + + val tableRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(nodeTable.node)) + .augmentation(FlowCapableNode).child(Table, new TableKey(nodeTable.ID as Short)).toInstance(); + + val it = this.startChange(); + + val table= it.readConfigurationData(tableRef) as Table; + + if(table != null){ + val tableStats = table.getAugmentation(FlowTableStatisticsData); + + if(tableStats != null){ + nodeStats = toNodeTableStatistics(tableStats.flowTableStatistics,table.id,nodeTable.node); + } + } + + //TODO: Refer TODO (main) val input = new GetFlowTablesStatisticsInputBuilder(); input.setNode(nodeTable.node.toNodeRef); flowTableStatisticsService.getFlowTablesStatistics(input.build); @@ -341,19 +358,22 @@ class InventoryAndReadAdapter implements IPluginInReadService, } override onNodeConnectorRemoved(NodeConnectorRemoved update) { - // NOOP + // Never received } override onNodeRemoved(NodeRemoved notification) { val properties = Collections.emptySet(); + removeNodeConnectors(notification.nodeRef.value); + publishNodeUpdate(notification.nodeRef.toADNode, UpdateType.REMOVED, properties); } override onNodeConnectorUpdated(NodeConnectorUpdated update) { var updateType = UpdateType.CHANGED; - if ( this._dataService.readOperationalData(update.nodeConnectorRef.value as InstanceIdentifier) == null ){ + if(!isKnownNodeConnector(update.nodeConnectorRef.value)){ updateType = UpdateType.ADDED; + recordNodeConnector(update.nodeConnectorRef.value); } var nodeConnector = update.nodeConnectorRef.toADNodeConnector @@ -369,16 +389,16 @@ class InventoryAndReadAdapter implements IPluginInReadService, updateType = UpdateType.ADDED; } publishNodeUpdate(notification.nodeRef.toADNode, updateType, notification.toADNodeProperties); - - //Notify the listeners of IPluginOutReadService - + + //Notify the listeners of IPluginOutReadService + for (statsPublisher : statisticsPublisher){ - val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; + val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; val description = notification.nodeRef.toNodeDescription if(description != null) { - statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,description); - } - } + statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,description); + } + } } override getNodeProps() { @@ -461,50 +481,50 @@ class InventoryAndReadAdapter implements IPluginInReadService, private def toNodeConnectorStatistics( org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics nodeConnectorStatistics, NodeId nodeId, NodeConnectorId nodeConnectorId) { - - val it = new NodeConnectorStatistics(); - - receivePacketCount = nodeConnectorStatistics.packets.received.longValue; - transmitPacketCount = nodeConnectorStatistics.packets.transmitted.longValue; - - receiveByteCount = nodeConnectorStatistics.bytes.received.longValue; - transmitByteCount = nodeConnectorStatistics.bytes.transmitted.longValue; - - receiveDropCount = nodeConnectorStatistics.receiveDrops.longValue; - transmitDropCount = nodeConnectorStatistics.transmitDrops.longValue; - - receiveErrorCount = nodeConnectorStatistics.receiveErrors.longValue; - transmitErrorCount = nodeConnectorStatistics.transmitErrors.longValue; - - receiveFrameErrorCount = nodeConnectorStatistics.receiveFrameError.longValue; - receiveOverRunErrorCount = nodeConnectorStatistics.receiveOverRunError.longValue; - receiveCRCErrorCount = nodeConnectorStatistics.receiveCrcError.longValue; - collisionCount = nodeConnectorStatistics.collisionCount.longValue; - - val nodeConnectorRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(nodeId)) - .child(NodeConnector,new NodeConnectorKey(nodeConnectorId)).toInstance; - - nodeConnector = NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef)); - - return it; - } - - private def toNodeTableStatistics( - FlowTableStatistics tableStats, - Short tableId,Node node){ - var it = new NodeTableStatistics(); - - activeCount = tableStats.activeFlows.value.intValue; - lookupCount = tableStats.packetsLookedUp.value.intValue; - matchedCount = tableStats.packetsMatched.value.intValue; - name = tableId.toString; - nodeTable = new NodeTable(NodeMapping.MD_SAL_TYPE,tableId,node); - return it; - } - - private def toNodeDescription(NodeRef nodeRef){ - val capableNode = readFlowCapableNode(nodeRef); + + val it = new NodeConnectorStatistics(); + + receivePacketCount = nodeConnectorStatistics.packets.received.longValue; + transmitPacketCount = nodeConnectorStatistics.packets.transmitted.longValue; + + receiveByteCount = nodeConnectorStatistics.bytes.received.longValue; + transmitByteCount = nodeConnectorStatistics.bytes.transmitted.longValue; + + receiveDropCount = nodeConnectorStatistics.receiveDrops.longValue; + transmitDropCount = nodeConnectorStatistics.transmitDrops.longValue; + + receiveErrorCount = nodeConnectorStatistics.receiveErrors.longValue; + transmitErrorCount = nodeConnectorStatistics.transmitErrors.longValue; + + receiveFrameErrorCount = nodeConnectorStatistics.receiveFrameError.longValue; + receiveOverRunErrorCount = nodeConnectorStatistics.receiveOverRunError.longValue; + receiveCRCErrorCount = nodeConnectorStatistics.receiveCrcError.longValue; + collisionCount = nodeConnectorStatistics.collisionCount.longValue; + + val nodeConnectorRef = InstanceIdentifier.builder(Nodes) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(nodeId)) + .child(NodeConnector,new NodeConnectorKey(nodeConnectorId)).toInstance; + + nodeConnector = NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef)); + + return it; + } + + private def toNodeTableStatistics( + FlowTableStatistics tableStats, + Short tableId,Node node){ + var it = new NodeTableStatistics(); + + activeCount = tableStats.activeFlows.value.intValue; + lookupCount = tableStats.packetsLookedUp.value.intValue; + matchedCount = tableStats.packetsMatched.value.intValue; + name = tableId.toString; + nodeTable = new NodeTable(NodeMapping.MD_SAL_TYPE,tableId,node); + return it; + } + + private def toNodeDescription(NodeRef nodeRef){ + val capableNode = readFlowCapableNode(nodeRef); if(capableNode !=null) { val it = new NodeDescription() manufacturer = capableNode.manufacturer @@ -515,101 +535,148 @@ class InventoryAndReadAdapter implements IPluginInReadService, return it; } return null; - } + } def Edge toADEdge(Link link) { new Edge(link.source.toADNodeConnector,link.destination.toADNodeConnector) } - - /* - * OpendaylightFlowStatisticsListener interface implementation - */ - override onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) { + + /* + * OpendaylightFlowStatisticsListener interface implementation + */ + override onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) { //Ignoring this notification as there does not seem to be a way to bubble this up to AD-SAL - } - - override onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) { - - val adsalFlowsStatistics = new ArrayList(); - val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; - - for(flowStats : notification.flowAndStatisticsMapList){ - if(flowStats.tableId == 0) - adsalFlowsStatistics.add(toFlowOnNode(flowStats,nodeRef.toADNode)); - } - - for (statsPublisher : statisticsPublisher){ - statsPublisher.nodeFlowStatisticsUpdated(nodeRef.toADNode,adsalFlowsStatistics); - } - - } - /* - * OpendaylightFlowTableStatisticsListener interface implementation - */ - override onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) { - var adsalFlowTableStatistics = new ArrayList(); - - for(stats : notification.flowTableAndStatisticsMap){ - if (stats.tableId.value == 0){ - val it = new NodeTableStatistics(); - activeCount = stats.activeFlows.value.intValue; - lookupCount = stats.packetsLookedUp.value.longValue; - matchedCount = stats.packetsMatched.value.longValue; - - adsalFlowTableStatistics.add(it); - } - } - for (statsPublisher : statisticsPublisher){ - val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; - statsPublisher.nodeTableStatisticsUpdated(nodeRef.toADNode,adsalFlowTableStatistics); - } - } - - /* - * OpendaylightPortStatisticsUpdate interface implementation - */ - override onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) { - - val adsalPortStatistics = new ArrayList(); - - for(nodeConnectorStatistics : notification.nodeConnectorStatisticsAndPortNumberMap){ - adsalPortStatistics.add(toNodeConnectorStatistics(nodeConnectorStatistics,notification.id,nodeConnectorStatistics.nodeConnectorId)); - } - - for (statsPublisher : statisticsPublisher){ - val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; - statsPublisher.nodeConnectorStatisticsUpdated(nodeRef.toADNode,adsalPortStatistics); - } - - } - - private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap,Node node){ - - val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap,node)); - - byteCount = flowAndStatsMap.byteCount.value.longValue; - packetCount = flowAndStatsMap.packetCount.value.longValue; - durationSeconds = flowAndStatsMap.duration.second.value.intValue; - durationNanoseconds = flowAndStatsMap.duration.nanosecond.value.intValue; - - return it; - } - - override getConfiguredNotConnectedNodes() { + } + + override onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) { + + val adsalFlowsStatistics = new ArrayList(); + val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; + + for(flowStats : notification.flowAndStatisticsMapList){ + if(flowStats.tableId == 0) + adsalFlowsStatistics.add(toFlowOnNode(flowStats,nodeRef.toADNode)); + } + + for (statsPublisher : statisticsPublisher){ + statsPublisher.nodeFlowStatisticsUpdated(nodeRef.toADNode,adsalFlowsStatistics); + } + + } + /* + * OpendaylightFlowTableStatisticsListener interface implementation + */ + override onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) { + var adsalFlowTableStatistics = new ArrayList(); + + for(stats : notification.flowTableAndStatisticsMap){ + if (stats.tableId.value == 0){ + val it = new NodeTableStatistics(); + activeCount = stats.activeFlows.value.intValue; + lookupCount = stats.packetsLookedUp.value.longValue; + matchedCount = stats.packetsMatched.value.longValue; + + adsalFlowTableStatistics.add(it); + } + } + for (statsPublisher : statisticsPublisher){ + val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; + statsPublisher.nodeTableStatisticsUpdated(nodeRef.toADNode,adsalFlowTableStatistics); + } + } + + /* + * OpendaylightPortStatisticsUpdate interface implementation + */ + override onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) { + + val adsalPortStatistics = new ArrayList(); + + for(nodeConnectorStatistics : notification.nodeConnectorStatisticsAndPortNumberMap){ + adsalPortStatistics.add(toNodeConnectorStatistics(nodeConnectorStatistics,notification.id,nodeConnectorStatistics.nodeConnectorId)); + } + + for (statsPublisher : statisticsPublisher){ + val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; + statsPublisher.nodeConnectorStatisticsUpdated(nodeRef.toADNode,adsalPortStatistics); + } + + } + + private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap,Node node){ + + val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap,node)); + + byteCount = flowAndStatsMap.byteCount.value.longValue; + packetCount = flowAndStatsMap.packetCount.value.longValue; + durationSeconds = flowAndStatsMap.duration.second.value.intValue; + durationNanoseconds = flowAndStatsMap.duration.nanosecond.value.intValue; + + return it; + } + + override getConfiguredNotConnectedNodes() { return Collections.emptySet(); - } + } + + + private def publishNodeUpdate(Node node, UpdateType updateType, Set properties){ + for( publisher : inventoryPublisher){ + publisher.updateNode(node, updateType, properties); + } + } + + private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set properties){ + for( publisher : inventoryPublisher){ + publisher.updateNodeConnector(nodeConnector, updateType, properties); + } + } + + private def isKnownNodeConnector(InstanceIdentifier nodeConnectorIdentifier){ + if(nodeConnectorIdentifier.path.size() < 3) { + return false; + } + val nodePath = nodeConnectorIdentifier.path.get(1); + val nodeConnectorPath = nodeConnectorIdentifier.getPath().get(2); - private def publishNodeUpdate(Node node, UpdateType updateType, Set properties){ - for( publisher : inventoryPublisher){ - publisher.updateNode(node, updateType, properties); - } - } + val nodeConnectors = nodeToNodeConnectorsMap.get(nodePath); - private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set properties){ - for( publisher : inventoryPublisher){ - publisher.updateNodeConnector(nodeConnector, updateType, properties); - } - } + if(nodeConnectors == null){ + return false; + } + return nodeConnectors.contains(nodeConnectorPath); + } + + + private def recordNodeConnector(InstanceIdentifier nodeConnectorIdentifier){ + if(nodeConnectorIdentifier.path.size() < 3) { + return false; + } + + val nodePath = nodeConnectorIdentifier.path.get(1); + val nodeConnectorPath = nodeConnectorIdentifier.getPath().get(2); + + nodeToNodeConnectorsLock.lock(); + + try { + var nodeConnectors = nodeToNodeConnectorsMap.get(nodePath); + + if(nodeConnectors == null){ + nodeConnectors = new ArrayList(); + nodeToNodeConnectorsMap.put(nodePath, nodeConnectors); + } + + nodeConnectors.add(nodeConnectorPath); + } finally { + nodeToNodeConnectorsLock.unlock(); + } + } + + private def removeNodeConnectors(InstanceIdentifier nodeIdentifier){ + val nodePath = nodeIdentifier.path.get(1); + + nodeToNodeConnectorsMap.remove(nodePath); + } } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryNotificationProvider.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryNotificationProvider.java new file mode 100644 index 0000000000..23a98ff39a --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryNotificationProvider.java @@ -0,0 +1,59 @@ +package org.opendaylight.controller.sal.compatibility; + +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class InventoryNotificationProvider implements AutoCloseable{ + + private ListenerRegistration nodeConnectorDataChangeListenerRegistration; + + private NodeConnectorDataChangeListener nodeConnectorDataChangeListener; + + private DataProviderService dataProviderService; + + private List inventoryPublisher; + + private final static Logger LOG = LoggerFactory.getLogger(NodeConnectorDataChangeListener.class); + + public void start(){ + + LOG.info("InventoryNotificationProvider started"); + + if(dataProviderService != null + && inventoryPublisher!= null){ + + if(nodeConnectorDataChangeListener == null){ + InstanceIdentifier nodeConnectorPath = InstanceIdentifier.builder(Nodes.class).child(Node.class).child(NodeConnector.class).build(); + nodeConnectorDataChangeListener = new NodeConnectorDataChangeListener(); + nodeConnectorDataChangeListener.setInventoryPublisher(inventoryPublisher); + nodeConnectorDataChangeListenerRegistration = dataProviderService.registerDataChangeListener(nodeConnectorPath, nodeConnectorDataChangeListener); + } + + } + } + + @Override + public void close() throws Exception { + if(nodeConnectorDataChangeListenerRegistration != null){ + nodeConnectorDataChangeListenerRegistration.close(); + } + } + + public void setDataProviderService(DataProviderService dataProviderService) { + this.dataProviderService = dataProviderService; + } + + public void setInventoryPublisher(List inventoryPublisher) { + this.inventoryPublisher = inventoryPublisher; + } +} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeConnectorDataChangeListener.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeConnectorDataChangeListener.java new file mode 100644 index 0000000000..eebba74244 --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeConnectorDataChangeListener.java @@ -0,0 +1,77 @@ +package org.opendaylight.controller.sal.compatibility; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.controller.sal.core.ConstructionException; +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.core.Property; +import org.opendaylight.controller.sal.core.UpdateType; +import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +// org.opendaylight.controller.sal.compatibility.NodeConnectorDataChangeListener +public class NodeConnectorDataChangeListener implements DataChangeListener{ + private final static Logger LOG = LoggerFactory.getLogger(NodeConnectorDataChangeListener.class); + + private List inventoryPublisher; + + public List getInventoryPublisher() { + return this.inventoryPublisher; + } + + public void setInventoryPublisher(final List inventoryPublisher) { + this.inventoryPublisher = inventoryPublisher; + } + + @Override + public void onDataChanged(DataChangeEvent, DataObject> change) { + final Map,DataObject> createdOperationalData = change.getCreatedOperationalData(); + final Map,DataObject> updatedOperationalData = change.getUpdatedOperationalData(); + + final Set,DataObject>> createdEntries = createdOperationalData.entrySet(); + final Set,DataObject>> updatedEntries = new HashSet<>(); + + updatedEntries.addAll(updatedOperationalData.entrySet()); + updatedEntries.removeAll(createdEntries); + + for(final Map.Entry,DataObject> entry : createdEntries){ + publishNodeConnectorUpdate(entry, UpdateType.ADDED); + } + + for(final Map.Entry,DataObject> entry : updatedEntries){ + publishNodeConnectorUpdate(entry, UpdateType.CHANGED); + } + } + + private void publishNodeConnectorUpdate(final Map.Entry,DataObject> entry, final UpdateType updateType) { + if (entry.getKey().getTargetType().equals(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector.class)) { + NodeConnectorRef nodeConnectorRef = new NodeConnectorRef(entry.getKey()); + NodeConnector nodeConnector = null; + try { + nodeConnector = NodeMapping.toADNodeConnector(nodeConnectorRef); + } catch (ConstructionException e) { + e.printStackTrace(); + } + HashSet _aDNodeConnectorProperties = NodeMapping.toADNodeConnectorProperties((org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector) entry.getValue()); + this.publishNodeConnectorUpdate(nodeConnector, updateType, _aDNodeConnectorProperties); + } + } + + private void publishNodeConnectorUpdate(final NodeConnector nodeConnector, final UpdateType updateType, final Set properties) { + LOG.debug("Publishing NodeConnector " + updateType.toString() + " nodeConnector Id = " + nodeConnector.getNodeConnectorIdAsString()); + + List _inventoryPublisher = getInventoryPublisher(); + for (final IPluginOutInventoryService publisher : _inventoryPublisher) { + publisher.updateNodeConnector(nodeConnector, updateType, properties); + } + } +} diff --git a/opendaylight/md-sal/forwardingrules-manager/pom.xml b/opendaylight/md-sal/forwardingrules-manager/pom.xml index a949e45d67..00cbc18e7e 100644 --- a/opendaylight/md-sal/forwardingrules-manager/pom.xml +++ b/opendaylight/md-sal/forwardingrules-manager/pom.xml @@ -46,7 +46,6 @@ org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT org.opendaylight.controller @@ -56,12 +55,10 @@ org.opendaylight.controller.model model-flow-service - 1.1-SNAPSHOT org.opendaylight.controller.model model-flow-management - 1.1-SNAPSHOT org.opendaylight.yangtools @@ -70,7 +67,6 @@ org.opendaylight.controller sal-binding-broker-impl - 1.1-SNAPSHOT provided diff --git a/opendaylight/md-sal/inventory-manager/pom.xml b/opendaylight/md-sal/inventory-manager/pom.xml index ffdac63e4f..4d0465cba7 100644 --- a/opendaylight/md-sal/inventory-manager/pom.xml +++ b/opendaylight/md-sal/inventory-manager/pom.xml @@ -23,17 +23,14 @@ org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT org.opendaylight.controller.model model-flow-service - 1.1-SNAPSHOT org.opendaylight.controller.model model-inventory - 1.1-SNAPSHOT org.eclipse.xtend diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend index 1a66b3ba16..43f48a50e5 100644 --- a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend +++ b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend @@ -64,6 +64,8 @@ class FlowCapableInventoryProvider implements AutoCloseable { class NodeChangeCommiter implements OpendaylightInventoryListener { + static val LOG = LoggerFactory.getLogger(NodeChangeCommiter); + @Property val FlowCapableInventoryProvider manager; @@ -76,6 +78,9 @@ class NodeChangeCommiter implements OpendaylightInventoryListener { // Check path val it = manager.startChange() + + LOG.debug("removing node connector : " + ref.value.toString()); + removeOperationalData(ref.value as InstanceIdentifier); commit() } @@ -93,6 +98,8 @@ class NodeChangeCommiter implements OpendaylightInventoryListener { data.addAugmentation(FlowCapableNodeConnector, augment) } + LOG.debug("updating node connector : " + ref.value.toString()); + putOperationalData(ref.value as InstanceIdentifier, data.build()); commit() } @@ -101,6 +108,8 @@ class NodeChangeCommiter implements OpendaylightInventoryListener { val ref = node.nodeRef; val it = manager.startChange() + LOG.debug("removing node : " + ref.value.toString()); + removeOperationalData(ref.value as InstanceIdentifier); commit() } @@ -117,6 +126,8 @@ class NodeChangeCommiter implements OpendaylightInventoryListener { data.addAugmentation(FlowCapableNode, augment) } + LOG.debug("updating node : " + ref.value.toString()); + putOperationalData(ref.value as InstanceIdentifier, data.build()) commit() } diff --git a/opendaylight/md-sal/model/model-flow-management/pom.xml b/opendaylight/md-sal/model/model-flow-management/pom.xml index d81669532b..39f5060a32 100644 --- a/opendaylight/md-sal/model/model-flow-management/pom.xml +++ b/opendaylight/md-sal/model/model-flow-management/pom.xml @@ -29,7 +29,6 @@ org.opendaylight.yangtools.model opendaylight-l2-types - 2013.08.27.3 bundle diff --git a/opendaylight/md-sal/model/model-flow-statistics/pom.xml b/opendaylight/md-sal/model/model-flow-statistics/pom.xml index 13efc4c3ae..54f232234b 100644 --- a/opendaylight/md-sal/model/model-flow-statistics/pom.xml +++ b/opendaylight/md-sal/model/model-flow-statistics/pom.xml @@ -29,7 +29,6 @@ org.opendaylight.yangtools.model opendaylight-l2-types - 2013.08.27.3 bundle diff --git a/opendaylight/md-sal/model/model-topology/pom.xml b/opendaylight/md-sal/model/model-topology/pom.xml index cd44bd2472..8e9f623efc 100644 --- a/opendaylight/md-sal/model/model-topology/pom.xml +++ b/opendaylight/md-sal/model/model-topology/pom.xml @@ -20,7 +20,6 @@ org.opendaylight.controller.model model-inventory - 1.1-SNAPSHOT org.opendaylight.yangtools.model diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index 8b4e478429..f900c0b18c 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -137,6 +137,11 @@ sal-connector-api ${project.version} + + org.opendaylight.controller + sal-binding-api + ${project.version} + org.opendaylight.controller sal @@ -148,6 +153,16 @@ + + org.opendaylight.controller + sal-remote + ${project.version} + + + org.opendaylight.controller + sal-binding-util + ${project.version} + diff --git a/opendaylight/md-sal/sal-binding-api/pom.xml b/opendaylight/md-sal/sal-binding-api/pom.xml index 86e14e4f56..f90031b205 100644 --- a/opendaylight/md-sal/sal-binding-api/pom.xml +++ b/opendaylight/md-sal/sal-binding-api/pom.xml @@ -26,18 +26,15 @@ org.opendaylight.controller sal-common - 1.1-SNAPSHOT org.opendaylight.controller sal-common-api - ${project.version} org.osgi org.osgi.core - ${osgi.core.version} provided diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java index 33b384a94c..69a2108065 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java @@ -19,8 +19,6 @@ public interface RpcConsumerRegistry extends BindingAwareService { * Returns a session specific instance (implementation) of requested * YANG module implentation / service provided by consumer. * - * @param service - * Broker service * @return Session specific implementation of service */ T getRpcService(Class module); diff --git a/opendaylight/md-sal/sal-binding-broker/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index e5a74e42a1..5367498777 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -101,7 +101,7 @@ org.opendaylight.controller.sal.binding.impl.*, org.opendaylight.controller.sal.binding.codegen, org.opendaylight.controller.sal.binding.codegen.*, - org.opendaylight.controller.sal.binding.dom.*, + org.opendaylight.controller.sal.binding.osgi.*, @@ -156,22 +156,18 @@ org.opendaylight.controller sal-common-util - 1.1-SNAPSHOT org.opendaylight.controller sal-common-impl - 1.1-SNAPSHOT org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT org.opendaylight.controller sal-binding-util - 1.1-SNAPSHOT org.slf4j @@ -180,7 +176,6 @@ org.osgi org.osgi.core - ${osgi.core.version} provided @@ -209,12 +204,10 @@ org.opendaylight.controller sal-core-api - 1.1-SNAPSHOT org.opendaylight.controller sal-broker-impl - 1.1-SNAPSHOT compile @@ -234,7 +227,6 @@ org.opendaylight.controller sal-binding-config - 1.1-SNAPSHOT org.opendaylight.yangtools @@ -253,28 +245,23 @@ org.opendaylight.yangtools.model ietf-inet-types - 2010.09.24.3 - org.opendaylight.yangtools.model - ietf-topology-l3-unicast-igp - 2013.10.21.1 - test + org.opendaylight.yangtools.model + ietf-topology-l3-unicast-igp + test - org.opendaylight.controller.model - model-flow-base - 1.1-SNAPSHOT + org.opendaylight.controller.model + model-flow-base - org.opendaylight.controller.model - model-flow-service - 1.1-SNAPSHOT + org.opendaylight.controller.model + model-flow-service - org.opendaylight.controller.model - model-flow-statistics - 1.1-SNAPSHOT + org.opendaylight.controller.model + model-flow-statistics diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java index 286b0c378c..7357926b9e 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java @@ -7,17 +7,17 @@ */ package org.opendaylight.controller.config.yang.md.sal.binding.impl; -import java.util.concurrent.ExecutorService; - -import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; -import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; -import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedDataBrokerImpl; -import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; -import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; +import java.util.concurrent.ExecutorService; + +import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; +import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; +import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedDataBrokerImpl; +import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; /** * @@ -57,14 +57,14 @@ public final class DataBrokerImplModule extends dataBindingBroker = createStandAloneBroker(listeningExecutor); } dataBindingBroker.registerRuntimeBean(getRootRuntimeBeanRegistratorWrapper()); - + dataBindingBroker.setNotificationExecutor(SingletonHolder.getDefaultChangeEventExecutor()); return dataBindingBroker; } private BindingIndependentMappingService resolveMappingServiceDependency() { if(getMappingService() != null) { return getMappingServiceDependency(); } - + ServiceReference potentialMappingService = bundleContext.getServiceReference(BindingIndependentMappingService.class); if(potentialMappingService != null) { return bundleContext.getService(potentialMappingService); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java index 0762739c63..14006a3fce 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java @@ -7,10 +7,11 @@ */ package org.opendaylight.controller.config.yang.md.sal.binding.impl; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; import java.util.Hashtable; import java.util.Map.Entry; import java.util.Set; - import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; import org.opendaylight.yangtools.concepts.Delegator; import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl; @@ -27,9 +28,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; - /** * */ @@ -63,7 +61,7 @@ public final class RuntimeMappingModule extends @Override public java.lang.AutoCloseable createInstance() { - + RuntimeGeneratedMappingServiceProxy potential = tryToReuseGlobalInstance(); if(potential != null) { return potential; @@ -100,7 +98,7 @@ public final class RuntimeMappingModule extends BindingIndependentMappingService, // Delegator, // AutoCloseable { - + private BindingIndependentMappingService delegate; private ServiceReference reference; private BundleContext bundleContext; @@ -113,56 +111,48 @@ public final class RuntimeMappingModule extends this.delegate = Preconditions.checkNotNull(delegate); } - @Override public CodecRegistry getCodecRegistry() { return delegate.getCodecRegistry(); } - @Override public CompositeNode toDataDom(DataObject data) { return delegate.toDataDom(data); } - @Override public Entry toDataDom( Entry, DataObject> entry) { return delegate.toDataDom(entry); } - @Override public InstanceIdentifier toDataDom( org.opendaylight.yangtools.yang.binding.InstanceIdentifier path) { return delegate.toDataDom(path); } - @Override public DataObject dataObjectFromDataDom( org.opendaylight.yangtools.yang.binding.InstanceIdentifier path, CompositeNode result) throws DeserializationException { return delegate.dataObjectFromDataDom(path, result); } - @Override public org.opendaylight.yangtools.yang.binding.InstanceIdentifier fromDataDom(InstanceIdentifier entry) throws DeserializationException { return delegate.fromDataDom(entry); } - @Override public Set getRpcQNamesFor(Class service) { return delegate.getRpcQNamesFor(service); } - @Override - public DataContainer dataObjectFromDataDom(Class inputClass, CompositeNode domInput) { - return delegate.dataObjectFromDataDom(inputClass, domInput); - } - @Override public Optional> getRpcServiceClassFor(String namespace, String revision) { - return delegate.getRpcServiceClassFor(namespace, revision); + return delegate.getRpcServiceClassFor(namespace,revision); } + public DataContainer dataObjectFromDataDom(Class inputClass, CompositeNode domInput) { + return delegate.dataObjectFromDataDom(inputClass, domInput); + } + @Override public void close() throws Exception { if(delegate != null) { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java index 291677a79a..a0bbb28d9e 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java @@ -29,6 +29,7 @@ public class SingletonHolder { public static final NotificationInvokerFactory INVOKER_FACTORY = RPC_GENERATOR_IMPL.getInvokerFactory(); private static ListeningExecutorService NOTIFICATION_EXECUTOR = null; private static ListeningExecutorService COMMIT_EXECUTOR = null; + private static ListeningExecutorService CHANGE_EVENT_EXECUTOR = null; public static synchronized final ListeningExecutorService getDefaultNotificationExecutor() { if (NOTIFICATION_EXECUTOR == null) { @@ -64,4 +65,21 @@ public class SingletonHolder { ExecutorService executor = Executors.newCachedThreadPool(factory); return MoreExecutors.listeningDecorator(executor); } + + public static ExecutorService getDefaultChangeEventExecutor() { + if (CHANGE_EVENT_EXECUTOR == null) { + ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("md-sal-binding-change-%d").build(); + /* + * FIXME: this used to be newCacheThreadPool(), but MD-SAL does not have transaction + * ordering guarantees, which means that using a concurrent threadpool results + * in application data being committed in random order, potentially resulting + * in inconsistent data being present. Once proper primitives are introduced, + * concurrency can be reintroduced. + */ + ExecutorService executor = Executors.newSingleThreadExecutor(factory); + CHANGE_EVENT_EXECUTOR = MoreExecutors.listeningDecorator(executor); + } + + return CHANGE_EVENT_EXECUTOR; + } } 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 ddf67719dc..16d5a24cb5 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 @@ -7,7 +7,8 @@ */ package org.opendaylight.controller.sal.binding.impl; -import java.util.Set; +import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; @@ -19,12 +20,46 @@ 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; +import com.google.common.collect.ImmutableMap.Builder; +import com.google.common.collect.Maps; public class DataBrokerImpl extends AbstractDataBroker, DataObject, DataChangeListener> // implements DataProviderService, AutoCloseable { + private final static class ContainsWildcarded implements Predicate> { + + private final InstanceIdentifier key; + + public ContainsWildcarded(InstanceIdentifier key) { + this.key = key; + } + + @Override + public boolean apply(InstanceIdentifier input) { + return key.containsWildcarded(input); + } + } + + private final static class IsContainedWildcarded implements Predicate> { + + private final InstanceIdentifier key; + + public IsContainedWildcarded(InstanceIdentifier key) { + this.key = key; + } + + @Override + public boolean apply(InstanceIdentifier input) { + return input.containsWildcarded(key); + } + } + private final AtomicLong nextTransaction = new AtomicLong(); private final AtomicLong createdTransactionsCount = new AtomicLong(); @@ -110,16 +145,33 @@ public class DataBrokerImpl extends AbstractDataBroker key, - Set> paths) { - if (paths.contains(key)) { - return true; - } - for (InstanceIdentifier path : paths) { - if (key.containsWildcarded(path)) { - return true; + protected Predicate> createContainsPredicate(final + InstanceIdentifier key) { + return new ContainsWildcarded(key); + } + + @Override + protected Predicate> createIsContainedPredicate(final + InstanceIdentifier key) { + return new IsContainedWildcarded(key); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + protected Map, DataObject> deepGetBySubpath( + Map, DataObject> dataSet, + InstanceIdentifier path) { + Builder, DataObject> builder = ImmutableMap.builder(); + Map, DataObject> potential = Maps.filterKeys(dataSet, createIsContainedPredicate(path)); + for(Entry, DataObject> entry : potential.entrySet()) { + try { + builder.putAll(DataObjectReadingUtil.readData(entry.getValue(),(InstanceIdentifier)entry.getKey(),path)); + } catch (Exception e) { + // FIXME : Log exception; } } - return false; - } + return builder.build(); + + } + } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend index a7dcf80e8d..9a431fec74 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend @@ -23,10 +23,11 @@ import org.opendaylight.yangtools.yang.binding.Notification import org.slf4j.LoggerFactory import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder import com.google.common.collect.Multimaps import org.opendaylight.yangtools.concepts.util.ListenerRegistry -import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener import java.util.Set -import com.google.common.collect.ImmutableSet -import java.util.concurrent.Future - +import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener import java.util.Set +import java.util.Set +import com.google.common.collect.ImmutableSet +import java.util.concurrent.Future + class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable { val ListenerRegistry interestListeners = ListenerRegistry.create; @@ -105,14 +106,14 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab submitAll(executor,tasks); } - def submitAll(ExecutorService service, Set tasks) { + def submitAll(ExecutorService service, Set tasks) { val ret = ImmutableSet.>builder(); for(task : tasks) { ret.add(service.submit(task)); } - return ret.build(); + return ret.build(); } - + override registerNotificationListener(Class notificationType, NotificationListener listener) { val reg = new GenericNotificationRegistration(notificationType, listener, this); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java index 5292487d03..3ad1dabffe 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java @@ -7,8 +7,7 @@ */ package org.opendaylight.controller.sal.binding.impl; -import static com.google.common.base.Preconditions.checkState; - +import com.google.common.collect.ImmutableClassToInstanceMap; import org.opendaylight.controller.md.sal.binding.util.AbstractBindingSalProviderInstance; import org.opendaylight.controller.md.sal.binding.util.BindingContextUtils; import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; @@ -33,8 +32,7 @@ import org.opendaylight.yangtools.yang.binding.RpcService; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import com.google.common.collect.ImmutableClassToInstanceMap; +import static com.google.common.base.Preconditions.checkState; public class RootBindingAwareBroker implements // Mutable, // 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 5630664a67..e48ebbc057 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 @@ -45,8 +45,6 @@ import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider; import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter; -import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; -import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException; import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl; import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.GlobalRpcRegistrationListener; import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.RouterInstantiationListener; @@ -79,6 +77,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; +import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; +import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -113,11 +113,11 @@ public class BindingIndependentConnector implements // private DataProviderService baDataService; - private ConcurrentMap domOpenedTransactions = new ConcurrentHashMap<>(); - private ConcurrentMap bindingOpenedTransactions = new ConcurrentHashMap<>(); + private final ConcurrentMap domOpenedTransactions = new ConcurrentHashMap<>(); + private final ConcurrentMap bindingOpenedTransactions = new ConcurrentHashMap<>(); - private BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler(); - private DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler(); + private final BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler(); + private final DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler(); private Registration, DataObject>> baCommitHandlerRegistration; @@ -130,7 +130,7 @@ public class BindingIndependentConnector implements // // private ListenerRegistration // bindingToDomRpcManager; - private Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() { + private final Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() { @Override public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier input) { @@ -149,8 +149,6 @@ public class BindingIndependentConnector implements // private RpcProviderRegistryImpl baRpcRegistryImpl; - private org.opendaylight.controller.sal.dom.broker.spi.RpcRouter biRouter; - private NotificationProviderService baNotifyService; private NotificationPublishService domNotificationService; @@ -319,9 +317,6 @@ public class BindingIndependentConnector implements // baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance()); baRpcRegistryImpl.registerGlobalRpcRegistrationListener(domToBindingRpcManager.getInstance()); } - if (biRpcRegistry instanceof org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) { - biRouter = (org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) biRpcRegistry; - } rpcForwarding = true; } } @@ -413,8 +408,8 @@ public class BindingIndependentConnector implements // private class BindingToDomTransaction implements DataCommitTransaction, DataObject> { - private DataModificationTransaction backing; - private DataModification, DataObject> modification; + private final DataModificationTransaction backing; + private final DataModification, DataObject> modification; public BindingToDomTransaction(DataModificationTransaction backing, DataModification, DataObject> modification) { @@ -491,6 +486,7 @@ public class BindingIndependentConnector implements // // FIXME: do registration based on only active commit handlers. } + @Override public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction requestCommit( DataModification domTransaction) { Object identifier = domTransaction.getIdentifier(); @@ -587,9 +583,9 @@ public class BindingIndependentConnector implements // private final Set supportedRpcs; private final WeakReference> rpcServiceType; - private Set registrations; - private Map strategiesByQName = new HashMap<>(); - private WeakHashMap strategiesByMethod = new WeakHashMap<>(); + private final Set registrations; + private final Map strategiesByQName = new HashMap<>(); + private final WeakHashMap strategiesByMethod = new WeakHashMap<>(); public DomToBindingRpcForwarder(Class service) { this.rpcServiceType = new WeakReference>(service); @@ -771,10 +767,10 @@ public class BindingIndependentConnector implements // private class DefaultInvocationStrategy extends RpcInvocationStrategy { @SuppressWarnings("rawtypes") - private WeakReference inputClass; + private final WeakReference inputClass; @SuppressWarnings("rawtypes") - private WeakReference outputClass; + private final WeakReference outputClass; @SuppressWarnings({ "rawtypes", "unchecked" }) public DefaultInvocationStrategy(QName rpc, Method targetMethod, Class outputClass, @@ -803,10 +799,10 @@ public class BindingIndependentConnector implements // @Override public Future> forwardToDomBroker(DataObject input) { - if(biRouter != null) { + if(biRpcRegistry != null) { CompositeNode xml = mappingService.toDataDom(input); CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.> of(xml)); - RpcResult result = biRouter.invokeRpc(rpc, wrappedXml); + RpcResult result = biRpcRegistry.invokeRpc(rpc, wrappedXml); Object baResultValue = null; if (result.getResult() != null) { baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult()); @@ -825,6 +821,7 @@ public class BindingIndependentConnector implements // super(rpc, targetMethod); } + @Override public RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception { @SuppressWarnings("unchecked") Future> result = (Future>) targetMethod.invoke(rpcService); @@ -837,21 +834,21 @@ public class BindingIndependentConnector implements // return Futures.immediateFuture(null); } } - + private class NoOutputInvocationStrategy extends RpcInvocationStrategy { - + @SuppressWarnings("rawtypes") - private WeakReference inputClass; + private final WeakReference inputClass; @SuppressWarnings({ "rawtypes", "unchecked" }) - public NoOutputInvocationStrategy(QName rpc, Method targetMethod, + public NoOutputInvocationStrategy(QName rpc, Method targetMethod, Class inputClass) { super(rpc,targetMethod); this.inputClass = new WeakReference(inputClass); } - - + + @Override public RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception { DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput); @@ -865,10 +862,10 @@ public class BindingIndependentConnector implements // @Override public Future> forwardToDomBroker(DataObject input) { - if(biRouter != null) { + if(biRpcRegistry != null) { CompositeNode xml = mappingService.toDataDom(input); CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.>of(xml)); - RpcResult result = biRouter.invokeRpc(rpc, wrappedXml); + RpcResult result = biRpcRegistry.invokeRpc(rpc, wrappedXml); Object baResultValue = null; RpcResult baResult = Rpcs.getRpcResult(result.isSuccessful(), null, result.getErrors()); return Futures.>immediateFuture(baResult); @@ -902,12 +899,12 @@ public class BindingIndependentConnector implements // public void setDomNotificationService(NotificationPublishService domService) { this.domNotificationService = domService; } - + private class DomToBindingNotificationForwarder implements NotificationInterestListener, NotificationListener { - private ConcurrentMap>> notifications = new ConcurrentHashMap<>(); - private Set supportedNotifications = new HashSet<>(); - + private final ConcurrentMap>> notifications = new ConcurrentHashMap<>(); + private final Set supportedNotifications = new HashSet<>(); + @Override public Set getSupportedNotifications() { return Collections.unmodifiableSet(supportedNotifications); @@ -922,7 +919,7 @@ public class BindingIndependentConnector implements // if (potentialClass != null) { final DataContainer baNotification = mappingService.dataObjectFromDataDom(potentialClass, notification); - + if (baNotification instanceof Notification) { baNotifyService.publish((Notification) baNotification); } diff --git a/opendaylight/md-sal/sal-binding-config/pom.xml b/opendaylight/md-sal/sal-binding-config/pom.xml index d87e272032..cb71b4fd3a 100644 --- a/opendaylight/md-sal/sal-binding-config/pom.xml +++ b/opendaylight/md-sal/sal-binding-config/pom.xml @@ -100,12 +100,10 @@ org.opendaylight.controller config-api - 0.2.4-SNAPSHOT org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT diff --git a/opendaylight/md-sal/sal-binding-dom-it/pom.xml b/opendaylight/md-sal/sal-binding-dom-it/pom.xml index 8560848d5e..82e3d97572 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-dom-it/pom.xml @@ -52,31 +52,26 @@ org.ops4j.pax.exam pax-exam-container-native test - ${exam.version} org.opendaylight.controller sal-binding-broker-impl - 1.1-SNAPSHOT test org.opendaylight.controller sal-binding-broker-impl - 1.1-SNAPSHOT test-jar test org.opendaylight.controller.model model-flow-service - 1.1-SNAPSHOT test org.opendaylight.controller.model model-flow-management - 1.1-SNAPSHOT test diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java index 598743af90..90fa2be211 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java @@ -6,9 +6,11 @@ * 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.assertNull; +import static org.junit.Assert.assertTrue; import java.util.Collections; import java.util.Map; @@ -52,38 +54,42 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data private static final InstanceIdentifier NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) // .toInstance(); - private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier// .builder(NODES_INSTANCE_ID_BA) // .child(Node.class, NODE_KEY).toInstance(); - private static final InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BA = InstanceIdentifier// .builder(NODES_INSTANCE_ID_BA) // .child(Node.class, NODE_KEY) // .augmentation(FlowCapableNode.class) // - .child(SupportedActions.class) - .toInstance(); + .child(SupportedActions.class).toInstance(); + private static final InstanceIdentifier ALL_FLOW_CAPABLE_NODES = InstanceIdentifier // + .builder(NODES_INSTANCE_ID_BA) // + .child(Node.class) // + .augmentation(FlowCapableNode.class) // + .build(); private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = // org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // .node(Nodes.QNAME) // .nodeWithKey(Node.QNAME, NODE_KEY_BI) // .toInstance(); - private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, SupportedActions.QNAME.getLocalName()); - + private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, + SupportedActions.QNAME.getLocalName()); private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BI = // - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // - .node(Nodes.QNAME) // - .nodeWithKey(Node.QNAME, NODE_KEY_BI) // - .node(SUPPORTED_ACTIONS_QNAME) // - .toInstance(); - - private DataChangeEvent, DataObject> receivedChangeEvent; - + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // + .node(Nodes.QNAME) // + .nodeWithKey(Node.QNAME, NODE_KEY_BI) // + .node(SUPPORTED_ACTIONS_QNAME) // + .toInstance(); + private static final InstanceIdentifier FLOW_AUGMENTATION_PATH = InstanceIdentifier // + .builder(NODE_INSTANCE_ID_BA) // + .augmentation(FlowCapableNode.class) // + .build(); + private DataChangeEvent, DataObject> lastReceivedChangeEvent; /** * Test for Bug 148 @@ -93,7 +99,8 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data @Test public void putNodeAndAugmentation() throws Exception { - baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this); + baDataService.registerDataChangeListener(ALL_FLOW_CAPABLE_NODES, this); + NodeBuilder nodeBuilder = new NodeBuilder(); nodeBuilder.setId(new NodeId(NODE_ID)); @@ -102,7 +109,7 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build()); RpcResult result = baseTransaction.commit().get(); assertEquals(TransactionStatus.COMMITED, result.getResult()); - assertNotNull(receivedChangeEvent); + Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); assertNotNull(node); assertEquals(NODE_KEY, node.getKey()); @@ -114,13 +121,16 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data fnub.setDescription("Description Foo"); fnub.setSoftware("JUnit emulated"); FlowCapableNode fnu = fnub.build(); - InstanceIdentifier augmentIdentifier = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance(); + InstanceIdentifier augmentIdentifier = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA) + .augmentation(FlowCapableNode.class).toInstance(); DataModificationTransaction augmentedTransaction = baDataService.beginTransaction(); augmentedTransaction.putOperationalData(augmentIdentifier, fnu); result = augmentedTransaction.commit().get(); assertEquals(TransactionStatus.COMMITED, result.getResult()); + assertNotNull(lastReceivedChangeEvent); + assertTrue(lastReceivedChangeEvent.getCreatedOperationalData().containsKey(FLOW_AUGMENTATION_PATH)); Node augmentedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); assertNotNull(node); @@ -131,11 +141,14 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data assertEquals(fnu.getDescription(), readedAugmentation.getDescription()); assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); testNodeRemove(); + assertTrue(lastReceivedChangeEvent.getRemovedOperationalData().contains(FLOW_AUGMENTATION_PATH)); } @Test public void putNodeWithAugmentation() throws Exception { + baDataService.registerDataChangeListener(ALL_FLOW_CAPABLE_NODES, this); + NodeBuilder nodeBuilder = new NodeBuilder(); nodeBuilder.setId(new NodeId(NODE_ID)); nodeBuilder.setKey(NODE_KEY); @@ -151,23 +164,31 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data DataModificationTransaction baseTransaction = baDataService.beginTransaction(); baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build()); RpcResult result = baseTransaction.commit().get(); + + assertNotNull(lastReceivedChangeEvent); + assertTrue(lastReceivedChangeEvent.getCreatedOperationalData().containsKey(FLOW_AUGMENTATION_PATH)); + lastReceivedChangeEvent = null; assertEquals(TransactionStatus.COMMITED, result.getResult()); - FlowCapableNode readedAugmentation = (FlowCapableNode) baDataService.readOperationalData(InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance()); + FlowCapableNode readedAugmentation = (FlowCapableNode) baDataService.readOperationalData(InstanceIdentifier + .builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance()); assertNotNull(readedAugmentation); + assertEquals(fnu.getHardware(), readedAugmentation.getHardware()); testPutNodeConnectorWithAugmentation(); + lastReceivedChangeEvent = null; testNodeRemove(); - } + assertTrue(lastReceivedChangeEvent.getRemovedOperationalData().contains(FLOW_AUGMENTATION_PATH)); + } private void testPutNodeConnectorWithAugmentation() throws Exception { NodeConnectorKey ncKey = new NodeConnectorKey(new NodeConnectorId("test:0:0")); InstanceIdentifier ncPath = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA) - .child(NodeConnector.class, ncKey).toInstance(); + .child(NodeConnector.class, ncKey).toInstance(); InstanceIdentifier ncAugmentPath = InstanceIdentifier.builder(ncPath) - .augmentation(FlowCapableNodeConnector.class).toInstance(); + .augmentation(FlowCapableNodeConnector.class).toInstance(); NodeConnectorBuilder nc = new NodeConnectorBuilder(); nc.setKey(ncKey); @@ -181,7 +202,8 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data RpcResult result = baseTransaction.commit().get(); assertEquals(TransactionStatus.COMMITED, result.getResult()); - FlowCapableNodeConnector readedAugmentation = (FlowCapableNodeConnector) baDataService.readOperationalData(ncAugmentPath); + FlowCapableNodeConnector readedAugmentation = (FlowCapableNodeConnector) baDataService + .readOperationalData(ncAugmentPath); assertNotNull(readedAugmentation); assertEquals(fncb.getName(), readedAugmentation.getName()); } @@ -196,7 +218,7 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data assertNull(node); } - private void verifyNodes(Nodes nodes,Node original) { + private void verifyNodes(Nodes nodes, Node original) { assertNotNull(nodes); assertNotNull(nodes.getNode()); assertEquals(1, nodes.getNode().size()); @@ -212,8 +234,7 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data } - private void assertBindingIndependentVersion( - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) { + private void assertBindingIndependentVersion(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) { CompositeNode node = biDataService.readOperationalData(nodeId); assertNotNull(node); } @@ -224,7 +245,7 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data @Override public void onDataChanged(DataChangeEvent, DataObject> change) { - receivedChangeEvent = change; + lastReceivedChangeEvent = change; } } diff --git a/opendaylight/md-sal/sal-binding-it/pom.xml b/opendaylight/md-sal/sal-binding-it/pom.xml index eaf5984c63..9bc8a48214 100644 --- a/opendaylight/md-sal/sal-binding-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-it/pom.xml @@ -19,9 +19,6 @@ ../sal-binding-broker/target/jacoco.exec ../sal-binding-broker/target/jacoco-it.exec - 0.2.4-SNAPSHOT - 0.2.4-SNAPSHOT - 2.5.0 @@ -145,71 +142,58 @@ org.opendaylight.controller sal-binding-broker-impl - 1.1-SNAPSHOT provided org.ops4j.pax.exam pax-exam-container-native - ${exam.version} test org.ops4j.pax.exam pax-exam-junit4 - ${exam.version} test org.opendaylight.controller config-netconf-connector - ${netconf.version} test org.opendaylight.controller yang-store-impl - ${config.version} org.opendaylight.controller logback-config - ${config.version} org.opendaylight.controller config-persister-impl - ${config.version} org.opendaylight.controller config-persister-file-xml-adapter - ${config.version} org.eclipse.persistence org.eclipse.persistence.moxy - ${moxy.controller.version} org.eclipse.persistence org.eclipse.persistence.core - ${moxy.controller.version} org.opendaylight.controller netconf-impl - ${netconf.version} org.opendaylight.controller netconf-monitoring - ${netconf.version} org.opendaylight.controller netconf-client - ${netconf.version} org.ops4j.pax.exam @@ -223,29 +207,24 @@ org.ops4j.pax.exam pax-exam-link-mvn - ${exam.version} test equinoxSDK381 org.eclipse.osgi - 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.mockito @@ -255,18 +234,15 @@ org.opendaylight.controller.model model-flow-service - 1.1-SNAPSHOT provided org.opendaylight.controller config-manager - 0.2.4-SNAPSHOT org.opendaylight.controller.model model-flow-management - 1.1-SNAPSHOT provided diff --git a/opendaylight/md-sal/sal-binding-util/pom.xml b/opendaylight/md-sal/sal-binding-util/pom.xml index 747e4205e1..4842d8cf28 100644 --- a/opendaylight/md-sal/sal-binding-util/pom.xml +++ b/opendaylight/md-sal/sal-binding-util/pom.xml @@ -22,7 +22,6 @@ org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT diff --git a/opendaylight/md-sal/sal-common-api/pom.xml b/opendaylight/md-sal/sal-common-api/pom.xml index 5dd08d062d..8a2571c727 100644 --- a/opendaylight/md-sal/sal-common-api/pom.xml +++ b/opendaylight/md-sal/sal-common-api/pom.xml @@ -17,7 +17,6 @@ org.opendaylight.controller sal-common - 1.1-SNAPSHOT org.opendaylight.yangtools @@ -30,7 +29,6 @@ org.osgi org.osgi.core - 5.0.0 bundle diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/TransactionStatus.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/TransactionStatus.java index 92ff55175c..a8989c4ce8 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/TransactionStatus.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/TransactionStatus.java @@ -8,9 +8,26 @@ package org.opendaylight.controller.md.sal.common.api; public enum TransactionStatus { + /** + * The transaction has been freshly allocated. The user is still accessing + * it and it has not been sealed. + */ NEW, + /** + * The transaction has been completed by the user and sealed. It is currently + * awaiting execution. + */ SUBMITED, + /** + * The transaction has been successfully committed to backing store. + */ COMMITED, + /** + * The transaction has failed to commit due to some underlying issue. + */ FAILED, - CANCELED + /** + * Currently unused. + */ + CANCELED, } diff --git a/opendaylight/md-sal/sal-common-impl/pom.xml b/opendaylight/md-sal/sal-common-impl/pom.xml index 46493ddad0..d3504bd018 100644 --- a/opendaylight/md-sal/sal-common-impl/pom.xml +++ b/opendaylight/md-sal/sal-common-impl/pom.xml @@ -18,12 +18,10 @@ org.opendaylight.controller sal-common-api - 1.1-SNAPSHOT org.opendaylight.controller sal-common-util - 1.1-SNAPSHOT com.google.guava diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java index bfa4f36c18..274f084f01 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java @@ -42,7 +42,7 @@ public class RoutingUtils { private final Map> removal; private final Map> announcement; - public RouteChangeImpl(ImmutableMap> removal, ImmutableMap> announcement) { + public RouteChangeImpl(ImmutableMap> announcement, ImmutableMap> removal) { super(); this.removal = removal; this.announcement = announcement; diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.java new file mode 100644 index 0000000000..bfffb594cb --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.java @@ -0,0 +1,441 @@ +/** + * 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.md.sal.common.impl.service; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.eclipse.xtext.xbase.lib.Exceptions; +import org.opendaylight.controller.md.sal.common.api.RegistrationListener; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.DataChangePublisher; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration; +import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransactionFactory; +import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService; +import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.CompositeObjectRegistration; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.concepts.util.ListenerRegistry; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import com.google.common.util.concurrent.MoreExecutors; + +public abstract class AbstractDataBroker

, D extends Object, DCL extends DataChangeListener> + implements DataModificationTransactionFactory, DataReader, DataChangePublisher, + DataProvisionService { + private final static Logger LOG = LoggerFactory.getLogger(AbstractDataBroker.class); + + private ExecutorService executor; + + public ExecutorService getExecutor() { + return this.executor; + } + + public void setExecutor(final ExecutorService executor) { + this.executor = executor; + } + + private ExecutorService notificationExecutor = MoreExecutors.sameThreadExecutor(); + + public ExecutorService getNotificationExecutor() { + return this.notificationExecutor; + } + + public void setNotificationExecutor(final ExecutorService notificationExecutor) { + this.notificationExecutor = notificationExecutor; + } + + private AbstractDataReadRouter dataReadRouter; + + private final AtomicLong submittedTransactionsCount = new AtomicLong(); + + private final AtomicLong failedTransactionsCount = new AtomicLong(); + + private final AtomicLong finishedTransactionsCount = new AtomicLong(); + + public AbstractDataReadRouter getDataReadRouter() { + return this.dataReadRouter; + } + + public void setDataReadRouter(final AbstractDataReadRouter dataReadRouter) { + this.dataReadRouter = dataReadRouter; + } + + public AtomicLong getSubmittedTransactionsCount() { + return this.submittedTransactionsCount; + } + + public AtomicLong getFailedTransactionsCount() { + return this.failedTransactionsCount; + } + + public AtomicLong getFinishedTransactionsCount() { + return this.finishedTransactionsCount; + } + + private final Multimap> listeners = Multimaps + .synchronizedSetMultimap(HashMultimap.> create()); + + private final Multimap> commitHandlers = Multimaps + .synchronizedSetMultimap(HashMultimap.> create()); + + private final Lock registrationLock = new ReentrantLock(); + + private final ListenerRegistry>> commitHandlerRegistrationListeners = new ListenerRegistry>>(); + + public AbstractDataBroker() { + } + + protected ImmutableList> affectedCommitHandlers(final Set

paths) { + final Callable>> _function = new Callable>>() { + @Override + public ImmutableList> call() throws Exception { + Map>> _asMap = commitHandlers.asMap(); + Set>>> _entrySet = _asMap.entrySet(); + FluentIterable>>> _from = FluentIterable + .>>> from(_entrySet); + final Predicate>>> _function = new Predicate>>>() { + @Override + public boolean apply(final Entry>> it) { + P _key = it.getKey(); + boolean _isAffectedBy = isAffectedBy(_key, paths); + return _isAffectedBy; + } + }; + FluentIterable>>> _filter = _from + .filter(_function); + final Function>>, Collection>> _function_1 = new Function>>, Collection>>() { + @Override + public Collection> apply( + final Entry>> it) { + Collection> _value = it.getValue(); + return _value; + } + }; + FluentIterable> _transformAndConcat = _filter + .> transformAndConcat(_function_1); + final Function, DataCommitHandler> _function_2 = new Function, DataCommitHandler>() { + @Override + public DataCommitHandler apply(final DataCommitHandlerRegistrationImpl it) { + DataCommitHandler _instance = it.getInstance(); + return _instance; + } + }; + FluentIterable> _transform = _transformAndConcat + .> transform(_function_2); + return _transform.toList(); + } + }; + return AbstractDataBroker.>> withLock(this.registrationLock, _function); + } + + protected ImmutableList> probablyAffectedCommitHandlers(final HashSet

paths) { + final Callable>> _function = new Callable>>() { + @Override + public ImmutableList> call() throws Exception { + Map>> _asMap = commitHandlers.asMap(); + Set>>> _entrySet = _asMap.entrySet(); + FluentIterable>>> _from = FluentIterable + .>>> from(_entrySet); + final Predicate>>> _function = new Predicate>>>() { + @Override + public boolean apply(final Entry>> it) { + P _key = it.getKey(); + boolean _isProbablyAffectedBy = isProbablyAffectedBy(_key, paths); + return _isProbablyAffectedBy; + } + }; + FluentIterable>>> _filter = _from + .filter(_function); + final Function>>, Collection>> _function_1 = new Function>>, Collection>>() { + @Override + public Collection> apply( + final Entry>> it) { + Collection> _value = it.getValue(); + return _value; + } + }; + FluentIterable> _transformAndConcat = _filter + .> transformAndConcat(_function_1); + final Function, DataCommitHandler> _function_2 = new Function, DataCommitHandler>() { + @Override + public DataCommitHandler apply(final DataCommitHandlerRegistrationImpl it) { + DataCommitHandler _instance = it.getInstance(); + return _instance; + } + }; + FluentIterable> _transform = _transformAndConcat + .> transform(_function_2); + return _transform.toList(); + } + }; + return AbstractDataBroker.>> withLock(this.registrationLock, _function); + } + + protected Map deepGetBySubpath(final Map dataSet, final P path) { + return Collections. emptyMap(); + } + + @Override + public final D readConfigurationData(final P path) { + AbstractDataReadRouter _dataReadRouter = this.getDataReadRouter(); + return _dataReadRouter.readConfigurationData(path); + } + + @Override + public final D readOperationalData(final P path) { + AbstractDataReadRouter _dataReadRouter = this.getDataReadRouter(); + return _dataReadRouter.readOperationalData(path); + } + + private static T withLock(final Lock lock, final Callable method) { + lock.lock(); + try { + return method.call(); + } catch (Exception e) { + throw Exceptions.sneakyThrow(e); + } finally { + lock.unlock(); + } + } + + @Override + public final Registration> registerCommitHandler(final P path, + final DataCommitHandler commitHandler) { + synchronized (commitHandler) { + final DataCommitHandlerRegistrationImpl registration = new DataCommitHandlerRegistrationImpl( + path, commitHandler, this); + commitHandlers.put(path, registration); + LOG.trace("Registering Commit Handler {} for path: {}", commitHandler, path); + for (final ListenerRegistration>> listener : commitHandlerRegistrationListeners) { + try { + listener.getInstance().onRegister(registration); + } catch (Exception e) { + LOG.error("Unexpected exception in listener {} during invoking onRegister", listener.getInstance(), + e); + } + } + return registration; + } + } + + @Override + public final ListenerRegistration registerDataChangeListener(final P path, final DCL listener) { + synchronized (listeners) { + final DataChangeListenerRegistration reg = new DataChangeListenerRegistration(path, + listener, AbstractDataBroker.this); + listeners.put(path, reg); + final D initialConfig = getDataReadRouter().readConfigurationData(path); + final D initialOperational = getDataReadRouter().readOperationalData(path); + final DataChangeEvent event = createInitialListenerEvent(path, initialConfig, initialOperational); + listener.onDataChanged(event); + return reg; + } + } + + public final CompositeObjectRegistration> registerDataReader(final P path, + final DataReader reader) { + + final Registration> confReg = getDataReadRouter().registerConfigurationReader(path, reader); + final Registration> dataReg = getDataReadRouter().registerOperationalReader(path, reader); + return new CompositeObjectRegistration>(reader, Arrays.asList(confReg, dataReg)); + } + + @Override + public ListenerRegistration>> registerCommitHandlerListener( + final RegistrationListener> commitHandlerListener) { + final ListenerRegistration>> ret = this.commitHandlerRegistrationListeners + .register(commitHandlerListener); + return ret; + } + + protected DataChangeEvent createInitialListenerEvent(final P path, final D initialConfig, + final D initialOperational) { + InitialDataChangeEventImpl _initialDataChangeEventImpl = new InitialDataChangeEventImpl( + initialConfig, initialOperational); + return _initialDataChangeEventImpl; + } + + protected final void removeListener(final DataChangeListenerRegistration registration) { + synchronized (listeners) { + listeners.remove(registration.getPath(), registration); + } + } + + protected final void removeCommitHandler(final DataCommitHandlerRegistrationImpl registration) { + synchronized (commitHandlers) { + + commitHandlers.remove(registration.getPath(), registration); + LOG.trace("Removing Commit Handler {} for path: {}", registration.getInstance(), registration.getPath()); + for (final ListenerRegistration>> listener : commitHandlerRegistrationListeners) { + try { + listener.getInstance().onUnregister(registration); + } catch (Exception e) { + LOG.error("Unexpected exception in listener {} during invoking onUnregister", + listener.getInstance(), e); + } + } + } + + } + + protected final Collection>> getActiveCommitHandlers() { + return commitHandlers.entries(); + } + + protected ImmutableList> affectedListeners(final Set

paths) { + + synchronized (listeners) { + return FluentIterable // + .from(listeners.asMap().entrySet()) // + .filter(new Predicate>>>() { + @Override + public boolean apply(final Entry>> it) { + return isAffectedBy(it.getKey(), paths); + } + }) // + .transform( + new Function>>, ListenerStateCapture>() { + @Override + public ListenerStateCapture apply( + final Entry>> it) { + return new ListenerStateCapture(it.getKey(), it.getValue(), + createContainsPredicate(it.getKey())); + } + }) // + .toList(); + } + } + + protected ImmutableList> probablyAffectedListeners(final Set

paths) { + synchronized (listeners) { + return FluentIterable // + .from(listeners.asMap().entrySet()) // + .filter(new Predicate>>>() { + @Override + public boolean apply(final Entry>> it) { + return isProbablyAffectedBy(it.getKey(), paths); + } + }) // + .transform( + new Function>>, ListenerStateCapture>() { + @Override + public ListenerStateCapture apply( + final Entry>> it) { + return new ListenerStateCapture(it.getKey(), it.getValue(), + createIsContainedPredicate(it.getKey())); + } + }) // + .toList(); + } + } + + protected Predicate

createContainsPredicate(final P key) { + return new Predicate

() { + @Override + public boolean apply(final P other) { + return key.contains(other); + } + }; + } + + protected Predicate

createIsContainedPredicate(final P key) { + return new Predicate

() { + @Override + public boolean apply(final P other) { + return other.contains(key); + } + }; + } + + protected boolean isAffectedBy(final P key, final Set

paths) { + final Predicate

contains = this.createContainsPredicate(key); + if (paths.contains(key)) { + return true; + } + for (final P path : paths) { + if (contains.apply(path)) { + return true; + } + } + return false; + } + + protected boolean isProbablyAffectedBy(final P key, final Set

paths) { + final Predicate

isContained = this.createIsContainedPredicate(key); + for (final P path : paths) { + if (isContained.apply(path)) { + return true; + } + } + return false; + } + + final Future> commit(final AbstractDataTransaction transaction) { + Preconditions.checkNotNull(transaction); + transaction.changeStatus(TransactionStatus.SUBMITED); + final TwoPhaseCommit task = new TwoPhaseCommit(transaction, this); + ; + this.getSubmittedTransactionsCount().getAndIncrement(); + return this.getExecutor().submit(task); + } + + private static class DataCommitHandlerRegistrationImpl

, D extends Object> // + extends AbstractObjectRegistration> // + implements DataCommitHandlerRegistration { + + private AbstractDataBroker dataBroker; + private final P path; + + @Override + public P getPath() { + return this.path; + } + + public DataCommitHandlerRegistrationImpl(final P path, final DataCommitHandler instance, + final AbstractDataBroker broker) { + super(instance); + this.dataBroker = broker; + this.path = path; + } + + @Override + protected void removeRegistration() { + this.dataBroker.removeCommitHandler(this); + this.dataBroker = null; + } + } +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend deleted file mode 100644 index 7c6f52f110..0000000000 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend +++ /dev/null @@ -1,443 +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.md.sal.common.impl.service - -import com.google.common.collect.FluentIterable -import com.google.common.collect.HashMultimap -import com.google.common.collect.ImmutableList -import com.google.common.collect.Multimap -import java.util.ArrayList -import java.util.Arrays -import java.util.Collection -import java.util.Collections -import java.util.HashSet -import java.util.List -import java.util.Set -import java.util.concurrent.Callable -import java.util.concurrent.ExecutorService -import java.util.concurrent.Future -import java.util.concurrent.atomic.AtomicLong -import org.opendaylight.controller.md.sal.common.api.RegistrationListener -import org.opendaylight.controller.md.sal.common.api.TransactionStatus -import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener -import org.opendaylight.controller.md.sal.common.api.data.DataChangePublisher -import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler -import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction -import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration -import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransactionFactory -import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService -import org.opendaylight.controller.md.sal.common.api.data.DataReader -import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification -import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter -import org.opendaylight.controller.sal.common.util.Rpcs -import org.opendaylight.yangtools.concepts.AbstractObjectRegistration -import org.opendaylight.yangtools.concepts.CompositeObjectRegistration -import org.opendaylight.yangtools.concepts.ListenerRegistration -import org.opendaylight.yangtools.concepts.Path -import org.opendaylight.yangtools.concepts.util.ListenerRegistry -import org.opendaylight.yangtools.yang.common.RpcResult -import org.slf4j.LoggerFactory - -import static com.google.common.base.Preconditions.* import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent -import com.google.common.collect.Multimaps -import java.util.concurrent.locks.Lock -import java.util.concurrent.locks.ReentrantLock - -abstract class AbstractDataBroker

, D, DCL extends DataChangeListener> implements DataModificationTransactionFactory, // -DataReader, // -DataChangePublisher, // -DataProvisionService { - - private static val LOG = LoggerFactory.getLogger(AbstractDataBroker); - - @Property - var ExecutorService executor; - - @Property - var AbstractDataReadRouter dataReadRouter; - - @Property - private val AtomicLong submittedTransactionsCount = new AtomicLong; - - @Property - private val AtomicLong failedTransactionsCount = new AtomicLong - - @Property - private val AtomicLong finishedTransactionsCount = new AtomicLong - - Multimap> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.create()); - Multimap> commitHandlers = Multimaps.synchronizedSetMultimap(HashMultimap.create()); - - private val Lock registrationLock = new ReentrantLock; - - val ListenerRegistry>> commitHandlerRegistrationListeners = new ListenerRegistry(); - public new() { - } - - protected def /*Iterator>,D>>*/ affectedCommitHandlers( - HashSet

paths) { - return withLock(registrationLock) [| - return FluentIterable.from(commitHandlers.asMap.entrySet).filter[key.isAffectedBy(paths)] // - .transformAndConcat[value] // - .transform[instance].toList() - ] - } - - override final readConfigurationData(P path) { - return dataReadRouter.readConfigurationData(path); - } - - override final readOperationalData(P path) { - return dataReadRouter.readOperationalData(path); - } - - private static def withLock(Lock lock,Callable method) { - lock.lock - try { - return method.call - } finally { - lock.unlock - } - } - - override final registerCommitHandler(P path, DataCommitHandler commitHandler) { - return withLock(registrationLock) [| - val registration = new DataCommitHandlerRegistrationImpl(path, commitHandler, this); - commitHandlers.put(path, registration) - LOG.trace("Registering Commit Handler {} for path: {}",commitHandler,path); - for(listener : commitHandlerRegistrationListeners) { - try { - listener.instance.onRegister(registration); - } catch (Exception e) { - LOG.error("Unexpected exception in listener {} during invoking onRegister",listener.instance,e); - } - } - return registration; - ] - } - - override final def registerDataChangeListener(P path, DCL listener) { - return withLock(registrationLock) [| - val reg = new DataChangeListenerRegistration(path, listener, this); - listeners.put(path, reg); - val initialConfig = dataReadRouter.readConfigurationData(path); - val initialOperational = dataReadRouter.readOperationalData(path); - val event = createInitialListenerEvent(path,initialConfig,initialOperational); - listener.onDataChanged(event); - return reg; - ] - } - - final def registerDataReader(P path, DataReader reader) { - return withLock(registrationLock) [| - val confReg = dataReadRouter.registerConfigurationReader(path, reader); - val dataReg = dataReadRouter.registerOperationalReader(path, reader); - - return new CompositeObjectRegistration(reader, Arrays.asList(confReg, dataReg)); - ] - } - - override registerCommitHandlerListener(RegistrationListener> commitHandlerListener) { - val ret = commitHandlerRegistrationListeners.register(commitHandlerListener); - return ret; - } - - protected def DataChangeEvent createInitialListenerEvent(P path,D initialConfig,D initialOperational) { - return new InitialDataChangeEventImpl(initialConfig,initialOperational); - - } - - protected final def removeListener(DataChangeListenerRegistration registration) { - return withLock(registrationLock) [| - listeners.remove(registration.path, registration); - ] - } - - protected final def removeCommitHandler(DataCommitHandlerRegistrationImpl registration) { - return withLock(registrationLock) [| - commitHandlers.remove(registration.path, registration); - LOG.trace("Removing Commit Handler {} for path: {}",registration.instance,registration.path); - for(listener : commitHandlerRegistrationListeners) { - try { - listener.instance.onUnregister(registration); - } catch (Exception e) { - LOG.error("Unexpected exception in listener {} during invoking onUnregister",listener.instance,e); - } - } - return null; - ] - } - - protected final def getActiveCommitHandlers() { - return commitHandlers.entries; - } - - protected def /*Iterator>,D>>*/ affectedListenersWithInitialState( - HashSet

paths) { - return withLock(registrationLock) [| - return FluentIterable.from(listeners.asMap.entrySet).filter[key.isAffectedBy(paths)].transform [ - val operationalState = readOperationalData(key) - val configurationState = readConfigurationData(key) - return new ListenerStateCapture(key, value, operationalState, configurationState) - ].toList() - ] - } - - protected def boolean isAffectedBy(P key, Set

paths) { - if (paths.contains(key)) { - return true; - } - for (path : paths) { - if (key.contains(path)) { - return true; - } - } - - return false; - } - - package final def Future> commit(AbstractDataTransaction transaction) { - checkNotNull(transaction); - transaction.changeStatus(TransactionStatus.SUBMITED); - val task = new TwoPhaseCommit(transaction, this); - submittedTransactionsCount.andIncrement; - return executor.submit(task); - } - -} - -@Data -package class ListenerStateCapture

, D, DCL extends DataChangeListener> { - - @Property - P path; - - @Property - Collection> listeners; - - @Property - D initialOperationalState; - - @Property - D initialConfigurationState; -} - -package class DataChangeListenerRegistration

, D, DCL extends DataChangeListener> extends AbstractObjectRegistration implements ListenerRegistration { - - AbstractDataBroker dataBroker; - - @Property - val P path; - - new(P path, DCL instance, AbstractDataBroker broker) { - super(instance) - dataBroker = broker; - _path = path; - } - - override protected removeRegistration() { - dataBroker.removeListener(this); - dataBroker = null; - } - -} - -package class DataCommitHandlerRegistrationImpl

, D> // -extends AbstractObjectRegistration> // -implements DataCommitHandlerRegistration { - - AbstractDataBroker dataBroker; - - @Property - val P path; - - new(P path, DataCommitHandler instance, AbstractDataBroker broker) { - super(instance) - dataBroker = broker; - _path = path; - } - - override protected removeRegistration() { - dataBroker.removeCommitHandler(this); - dataBroker = null; - } -} - -package class TwoPhaseCommit

, D, DCL extends DataChangeListener> implements Callable> { - - private static val log = LoggerFactory.getLogger(TwoPhaseCommit); - - val AbstractDataTransaction transaction; - val AbstractDataBroker dataBroker; - - new(AbstractDataTransaction transaction, AbstractDataBroker broker) { - this.transaction = transaction; - this.dataBroker = broker; - } - - override call() throws Exception { - - // get affected paths - val affectedPaths = new HashSet

(); - - affectedPaths.addAll(transaction.createdConfigurationData.keySet); - affectedPaths.addAll(transaction.updatedConfigurationData.keySet); - affectedPaths.addAll(transaction.removedConfigurationData); - - affectedPaths.addAll(transaction.createdOperationalData.keySet); - affectedPaths.addAll(transaction.updatedOperationalData.keySet); - affectedPaths.addAll(transaction.removedOperationalData); - - val listeners = dataBroker.affectedListenersWithInitialState(affectedPaths); - - val transactionId = transaction.identifier; - - log.trace("Transaction: {} Started.",transactionId); - log.trace("Transaction: {} Affected Subtrees:",transactionId,affectedPaths); - // requesting commits - val Iterable> commitHandlers = dataBroker.affectedCommitHandlers(affectedPaths); - val List> handlerTransactions = new ArrayList(); - try { - for (handler : commitHandlers) { - handlerTransactions.add(handler.requestCommit(transaction)); - } - } catch (Exception e) { - log.error("Transaction: {} Request Commit failed", transactionId,e); - dataBroker.failedTransactionsCount.andIncrement - transaction.changeStatus(TransactionStatus.FAILED) - return rollback(handlerTransactions, e); - } - val List> results = new ArrayList(); - try { - for (subtransaction : handlerTransactions) { - results.add(subtransaction.finish()); - } - listeners.publishDataChangeEvent(); - } catch (Exception e) { - log.error("Transaction: {} Finish Commit failed",transactionId, e); - dataBroker.failedTransactionsCount.andIncrement - transaction.changeStatus(TransactionStatus.FAILED) - return rollback(handlerTransactions, e); - } - log.trace("Transaction: {} Finished successfully.",transactionId); - dataBroker.finishedTransactionsCount.andIncrement; - transaction.changeStatus(TransactionStatus.COMMITED) - return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet()); - - } - - def void publishDataChangeEvent(ImmutableList> listeners) { - dataBroker.executor.submit [| - for (listenerSet : listeners) { - val updatedConfiguration = dataBroker.readConfigurationData(listenerSet.path); - val updatedOperational = dataBroker.readOperationalData(listenerSet.path); - - val changeEvent = new DataChangeEventImpl(transaction, listenerSet.initialConfigurationState, - listenerSet.initialOperationalState, updatedOperational, updatedConfiguration); - for (listener : listenerSet.listeners) { - try { - listener.instance.onDataChanged(changeEvent); - - } catch (Exception e) { - e.printStackTrace(); - } - } - } - ] - } - - def rollback(List> transactions, Exception e) { - for (transaction : transactions) { - transaction.rollback() - } - - // FIXME return encountered error. - return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.emptySet()); - } -} - -public abstract class AbstractDataTransaction

, D> extends AbstractDataModification { - - private static val LOG = LoggerFactory.getLogger(AbstractDataTransaction); - - @Property - private val Object identifier; - - var TransactionStatus status; - - var AbstractDataBroker broker; - - protected new(Object identifier,AbstractDataBroker dataBroker) { - super(dataBroker); - _identifier = identifier; - broker = dataBroker; - status = TransactionStatus.NEW; - LOG.debug("Transaction {} Allocated.", identifier); - - //listeners = new ListenerRegistry<>(); - } - - override commit() { - return broker.commit(this); - } - - override readConfigurationData(P path) { - val local = this.updatedConfigurationData.get(path); - if(local != null) { - return local; - } - - return broker.readConfigurationData(path); - } - - override readOperationalData(P path) { - val local = this.updatedOperationalData.get(path); - if(local != null) { - return local; - } - return broker.readOperationalData(path); - } - - override hashCode() { - return identifier.hashCode; - } - - override equals(Object obj) { - if (this === obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - val other = (obj as AbstractDataTransaction); - if (broker == null) { - if (other.broker != null) - return false; - } else if (!broker.equals(other.broker)) - return false; - if (identifier == null) { - if (other.identifier != null) - return false; - } else if (!identifier.equals(other.identifier)) - return false; - return true; - } - - override TransactionStatus getStatus() { - return status; - } - - protected abstract def void onStatusChange(TransactionStatus status); - - public def changeStatus(TransactionStatus status) { - LOG.debug("Transaction {} transitioned from {} to {}", identifier, this.status, status); - this.status = status; - onStatusChange(status); - } - -} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java new file mode 100644 index 0000000000..c73a627799 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java @@ -0,0 +1,108 @@ +/** + * 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.md.sal.common.impl.service; + +import java.util.concurrent.Future; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification; +import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@SuppressWarnings("all") +public abstract class AbstractDataTransaction

, D extends Object> extends + AbstractDataModification { + private final static Logger LOG = LoggerFactory.getLogger(AbstractDataTransaction.class); + + private final Object identifier; + + @Override + public Object getIdentifier() { + return this.identifier; + } + + private TransactionStatus status; + + private final AbstractDataBroker broker; + + protected AbstractDataTransaction(final Object identifier, + final AbstractDataBroker dataBroker) { + super(dataBroker); + this.identifier = identifier; + this.broker = dataBroker; + this.status = TransactionStatus.NEW; + AbstractDataTransaction.LOG.debug("Transaction {} Allocated.", identifier); + } + + @Override + public Future> commit() { + return this.broker.commit(this); + } + + @Override + public D readConfigurationData(final P path) { + final D local = getUpdatedConfigurationData().get(path); + if (local != null) { + return local; + } + return this.broker.readConfigurationData(path); + } + + @Override + public D readOperationalData(final P path) { + final D local = this.getUpdatedOperationalData().get(path); + if (local != null) { + return local; + } + return this.broker.readOperationalData(path); + } + + + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((identifier == null) ? 0 : identifier.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AbstractDataTransaction other = (AbstractDataTransaction) obj; + if (identifier == null) { + if (other.identifier != null) + return false; + } else if (!identifier.equals(other.identifier)) + return false; + return true; + } + + @Override + public TransactionStatus getStatus() { + return this.status; + } + + protected abstract void onStatusChange(final TransactionStatus status); + + public void changeStatus(final TransactionStatus status) { + Object _identifier = this.getIdentifier(); + AbstractDataTransaction.LOG + .debug("Transaction {} transitioned from {} to {}", _identifier, this.status, status); + this.status = status; + this.onStatusChange(status); + } +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java index 7f5e466c00..691c303688 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java @@ -20,8 +20,6 @@ public class DataChangeEventImpl

, D> implements DataChangeEven private final DataChange dataChange; private final D originalConfigurationSubtree; - - private final D originalOperationalSubtree; private final D updatedOperationalSubtree; private final D updatedConfigurationSubtree; diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeListenerRegistration.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeListenerRegistration.java new file mode 100644 index 0000000000..57d511ecf2 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeListenerRegistration.java @@ -0,0 +1,37 @@ +/** + * 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.md.sal.common.impl.service; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Path; + +@SuppressWarnings("all") +class DataChangeListenerRegistration

, D extends Object, DCL extends DataChangeListener> extends + AbstractObjectRegistration implements ListenerRegistration { + private AbstractDataBroker dataBroker; + + private final P path; + + public P getPath() { + return this.path; + } + + public DataChangeListenerRegistration(final P path, final DCL instance, final AbstractDataBroker broker) { + super(instance); + this.dataBroker = broker; + this.path = path; + } + + @Override + protected void removeRegistration() { + this.dataBroker.removeListener(this); + this.dataBroker = null; + } +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java new file mode 100644 index 0000000000..776ff7bfb2 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java @@ -0,0 +1,226 @@ +package org.opendaylight.controller.md.sal.common.impl.service; + +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.yangtools.concepts.Path; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; + +final class ImmutableDataChangeEvent

, D> implements DataChangeEvent { + + private final D updatedOperationalSubtree; + private final Map updatedOperational; + private final D updatedConfigurationSubtree; + private final Map updatedConfiguration; + private final Set

removedOperational; + private final Set

removedConfiguration; + private final D originalOperationalSubtree; + private final Map originalOperational; + private final D originalConfigurationSubtree; + private final Map originalConfiguration; + private final Map createdOperational; + private final Map createdConfiguration; + + + public ImmutableDataChangeEvent(Builder builder) { + + createdConfiguration = builder.getCreatedConfiguration().build(); + createdOperational = builder.getCreatedOperational().build(); + originalConfiguration = builder.getOriginalConfiguration().build(); + originalConfigurationSubtree = builder.getOriginalConfigurationSubtree(); + originalOperational = builder.getOriginalOperational().build(); + originalOperationalSubtree = builder.getOriginalOperationalSubtree(); + removedConfiguration = builder.getRemovedConfiguration().build(); + removedOperational = builder.getRemovedOperational().build(); + updatedConfiguration = builder.getUpdatedConfiguration().build(); + updatedConfigurationSubtree = builder.getUpdatedConfigurationSubtree(); + updatedOperational = builder.getUpdatedOperational().build(); + updatedOperationalSubtree = builder.getUpdatedOperationalSubtree(); + } + + @Override + public Map getCreatedConfigurationData() { + return createdConfiguration; + } + + @Override + public Map getCreatedOperationalData() { + return createdOperational; + } + + @Override + public Map getOriginalConfigurationData() { + return originalConfiguration; + } + @Override + public D getOriginalConfigurationSubtree() { + return originalConfigurationSubtree; + } + @Override + public Map getOriginalOperationalData() { + return originalOperational; + } + @Override + public D getOriginalOperationalSubtree() { + return originalOperationalSubtree; + } + @Override + public Set

getRemovedConfigurationData() { + return removedConfiguration; + } + @Override + public Set

getRemovedOperationalData() { + return removedOperational; + } + @Override + public Map getUpdatedConfigurationData() { + return updatedConfiguration; + } + @Override + public D getUpdatedConfigurationSubtree() { + return updatedConfigurationSubtree; + } + @Override + public Map getUpdatedOperationalData() { + return updatedOperational; + } + @Override + public D getUpdatedOperationalSubtree() { + return updatedOperationalSubtree; + } + + static final

,D> Builder builder() { + return new Builder<>(); + } + + static final class Builder

,D> { + + private D updatedOperationalSubtree; + private D originalOperationalSubtree; + private D originalConfigurationSubtree; + private D updatedConfigurationSubtree; + + private final ImmutableMap.Builder updatedOperational = ImmutableMap.builder(); + private final ImmutableMap.Builder updatedConfiguration = ImmutableMap.builder(); + private final ImmutableSet.Builder

removedOperational = ImmutableSet.builder(); + private final ImmutableSet.Builder

removedConfiguration = ImmutableSet.builder(); + private final ImmutableMap.Builder originalOperational = ImmutableMap.builder(); + + private final ImmutableMap.Builder originalConfiguration = ImmutableMap.builder(); + private final ImmutableMap.Builder createdOperational = ImmutableMap.builder(); + private final ImmutableMap.Builder createdConfiguration = ImmutableMap.builder(); + + + protected Builder addTransaction(DataModification data, Predicate

keyFilter) { + updatedOperational.putAll(Maps.filterKeys(data.getUpdatedOperationalData(), keyFilter)); + updatedConfiguration.putAll(Maps.filterKeys(data.getUpdatedConfigurationData(), keyFilter)); + originalConfiguration.putAll(Maps.filterKeys(data.getOriginalConfigurationData(), keyFilter)); + originalOperational.putAll(Maps.filterKeys(data.getOriginalOperationalData(), keyFilter)); + createdOperational.putAll(Maps.filterKeys(data.getCreatedOperationalData(), keyFilter)); + createdConfiguration.putAll(Maps.filterKeys(data.getCreatedConfigurationData(), keyFilter)); + return this; + } + + protected Builder addConfigurationChangeSet(RootedChangeSet changeSet) { + if(changeSet == null) { + return this; + } + + originalConfiguration.putAll(changeSet.getOriginal()); + createdConfiguration.putAll(changeSet.getCreated()); + updatedConfiguration.putAll(changeSet.getUpdated()); + removedConfiguration.addAll(changeSet.getRemoved()); + return this; + } + + protected Builder addOperationalChangeSet(RootedChangeSet changeSet) { + if(changeSet == null) { + return this; + } + originalOperational.putAll(changeSet.getOriginal()); + createdOperational.putAll(changeSet.getCreated()); + updatedOperational.putAll(changeSet.getUpdated()); + removedOperational.addAll(changeSet.getRemoved()); + return this; + } + + protected ImmutableDataChangeEvent build() { + return new ImmutableDataChangeEvent(this); + } + + protected D getUpdatedOperationalSubtree() { + return updatedOperationalSubtree; + } + + protected Builder setUpdatedOperationalSubtree(D updatedOperationalSubtree) { + this.updatedOperationalSubtree = updatedOperationalSubtree; + return this; + } + + protected D getOriginalOperationalSubtree() { + return originalOperationalSubtree; + } + + protected Builder setOriginalOperationalSubtree(D originalOperationalSubtree) { + this.originalOperationalSubtree = originalOperationalSubtree; + return this; + } + + protected D getOriginalConfigurationSubtree() { + return originalConfigurationSubtree; + } + + protected Builder setOriginalConfigurationSubtree(D originalConfigurationSubtree) { + this.originalConfigurationSubtree = originalConfigurationSubtree; + return this; + } + + protected D getUpdatedConfigurationSubtree() { + return updatedConfigurationSubtree; + } + + protected Builder setUpdatedConfigurationSubtree(D updatedConfigurationSubtree) { + this.updatedConfigurationSubtree = updatedConfigurationSubtree; + return this; + } + + protected ImmutableMap.Builder getUpdatedOperational() { + return updatedOperational; + } + + protected ImmutableMap.Builder getUpdatedConfiguration() { + return updatedConfiguration; + } + + protected ImmutableSet.Builder

getRemovedOperational() { + return removedOperational; + } + + protected ImmutableSet.Builder

getRemovedConfiguration() { + return removedConfiguration; + } + + protected ImmutableMap.Builder getOriginalOperational() { + return originalOperational; + } + + protected ImmutableMap.Builder getOriginalConfiguration() { + return originalConfiguration; + } + + protected ImmutableMap.Builder getCreatedOperational() { + return createdOperational; + } + + protected ImmutableMap.Builder getCreatedConfiguration() { + return createdConfiguration; + } + } + +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ListenerStateCapture.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ListenerStateCapture.java new file mode 100644 index 0000000000..502ca90ab9 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ListenerStateCapture.java @@ -0,0 +1,118 @@ +package org.opendaylight.controller.md.sal.common.impl.service; + +import java.util.Map; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.yangtools.concepts.Path; + +import com.google.common.base.Predicate; + +public final class ListenerStateCapture

, D, DCL extends DataChangeListener> { + + final P path; + + final Iterable> listeners; + + D initialOperationalState; + + D initialConfigurationState; + + D finalConfigurationState; + + D finalOperationalState; + + Map additionalConfigOriginal; + Map additionalConfigCreated; + Map additionalConfigUpdated; + Map additionalConfigDeleted; + + Map additionalOperOriginal; + Map additionalOperCreated; + Map additionalOperUpdated; + Map additionalOperDeleted; + + RootedChangeSet normalizedConfigurationChanges; + RootedChangeSet normalizedOperationalChanges; + + private final Predicate

containsPredicate; + + public ListenerStateCapture(P path, Iterable> listeners, + Predicate

containsPredicate) { + super(); + this.path = path; + this.listeners = listeners; + this.containsPredicate = containsPredicate; + } + + protected D getInitialOperationalState() { + return initialOperationalState; + } + + protected void setInitialOperationalState(D initialOperationalState) { + this.initialOperationalState = initialOperationalState; + } + + protected D getInitialConfigurationState() { + return initialConfigurationState; + } + + protected void setInitialConfigurationState(D initialConfigurationState) { + this.initialConfigurationState = initialConfigurationState; + } + + protected P getPath() { + return path; + } + + protected Iterable> getListeners() { + return listeners; + } + + protected D getFinalConfigurationState() { + return finalConfigurationState; + } + + protected void setFinalConfigurationState(D finalConfigurationState) { + this.finalConfigurationState = finalConfigurationState; + } + + protected D getFinalOperationalState() { + return finalOperationalState; + } + + protected void setFinalOperationalState(D finalOperationalState) { + this.finalOperationalState = finalOperationalState; + } + + protected RootedChangeSet getNormalizedConfigurationChanges() { + return normalizedConfigurationChanges; + } + + protected void setNormalizedConfigurationChanges(RootedChangeSet normalizedConfigurationChanges) { + this.normalizedConfigurationChanges = normalizedConfigurationChanges; + } + + protected RootedChangeSet getNormalizedOperationalChanges() { + return normalizedOperationalChanges; + } + + protected void setNormalizedOperationalChanges(RootedChangeSet normalizedOperationalChange) { + this.normalizedOperationalChanges = normalizedOperationalChange; + } + + protected DataChangeEvent createEvent(DataModification modification) { + return ImmutableDataChangeEvent. builder()// + .addTransaction(modification, containsPredicate) // + .addConfigurationChangeSet(normalizedConfigurationChanges) // + .addOperationalChangeSet(normalizedOperationalChanges) // + .setOriginalConfigurationSubtree(initialConfigurationState) // + .setOriginalOperationalSubtree(initialOperationalState) // + .setUpdatedConfigurationSubtree(finalConfigurationState) // + .setUpdatedOperationalSubtree(finalOperationalState) // + .build(); + + } + +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/RootedChangeSet.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/RootedChangeSet.java new file mode 100644 index 0000000000..e0525657e5 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/RootedChangeSet.java @@ -0,0 +1,66 @@ +package org.opendaylight.controller.md.sal.common.impl.service; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.opendaylight.yangtools.concepts.Path; + +public class RootedChangeSet

,D> { + + private final P root; + private final Map original; + private final Map created = new HashMap<>(); + private final Map updated = new HashMap<>(); + private final Set

removed = new HashSet<>(); + + + + public RootedChangeSet(P root,Map original) { + super(); + this.root = root; + this.original = original; + } + + protected P getRoot() { + return root; + } + + protected Map getOriginal() { + return original; + } + + protected Map getCreated() { + return created; + } + + protected Map getUpdated() { + return updated; + } + + protected Set

getRemoved() { + return removed; + } + + public void addCreated(Map created) { + this.created.putAll(created); + } + + public void addCreated(Entry entry) { + created.put(entry.getKey(), entry.getValue()); + } + + public void addUpdated(Entry entry) { + updated.put(entry.getKey(), entry.getValue()); + } + + public void addRemoval(P path) { + removed.add(path); + } + + public boolean isChange() { + return !created.isEmpty() || !updated.isEmpty() || !removed.isEmpty(); + } +} 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 new file mode 100644 index 0000000000..e99fc0f24c --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java @@ -0,0 +1,237 @@ +/** + * 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.md.sal.common.impl.service; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; +import org.opendaylight.controller.sal.common.util.Rpcs; +import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +public class TwoPhaseCommit

, D extends Object, DCL extends DataChangeListener> implements + Callable> { + private final static Logger log = LoggerFactory.getLogger(TwoPhaseCommit.class); + + private final AbstractDataTransaction transaction; + + private final AbstractDataBroker dataBroker; + + public TwoPhaseCommit(final AbstractDataTransaction transaction, final AbstractDataBroker broker) { + this.transaction = transaction; + this.dataBroker = broker; + } + + @Override + public RpcResult call() throws Exception { + final Object transactionId = this.transaction.getIdentifier(); + + Set

changedPaths = ImmutableSet.

builder().addAll(transaction.getUpdatedConfigurationData().keySet()) + .addAll(transaction.getCreatedConfigurationData().keySet()) + .addAll(transaction.getRemovedConfigurationData()) + .addAll(transaction.getUpdatedOperationalData().keySet()) + .addAll(transaction.getCreatedOperationalData().keySet()) + .addAll(transaction.getRemovedOperationalData()).build(); + + log.trace("Transaction: {} Affected Subtrees:", transactionId, changedPaths); + + final ImmutableList.Builder> listenersBuilder = ImmutableList.builder(); + listenersBuilder.addAll(dataBroker.affectedListeners(changedPaths)); + filterProbablyAffectedListeners(dataBroker.probablyAffectedListeners(changedPaths),listenersBuilder); + + + + final ImmutableList> listeners = listenersBuilder.build(); + final Iterable> commitHandlers = dataBroker.affectedCommitHandlers(changedPaths); + captureInitialState(listeners); + + + log.trace("Transaction: {} Starting Request Commit.",transactionId); + final List> handlerTransactions = new ArrayList<>(); + try { + for (final DataCommitHandler handler : commitHandlers) { + DataCommitTransaction requestCommit = handler.requestCommit(this.transaction); + if (requestCommit != null) { + handlerTransactions.add(requestCommit); + } else { + log.debug("Transaction: {}, Handler {} is not participating in transaction.", transactionId, + handler); + } + } + } catch (Exception e) { + log.error("Transaction: {} Request Commit failed", transactionId, e); + dataBroker.getFailedTransactionsCount().getAndIncrement(); + this.transaction.changeStatus(TransactionStatus.FAILED); + return this.rollback(handlerTransactions, e); + + } + + log.trace("Transaction: {} Starting Finish.",transactionId); + final List> results = new ArrayList>(); + try { + for (final DataCommitTransaction subtransaction : handlerTransactions) { + results.add(subtransaction.finish()); + } + } catch (Exception e) { + log.error("Transaction: {} Finish Commit failed", transactionId, e); + dataBroker.getFailedTransactionsCount().getAndIncrement(); + transaction.changeStatus(TransactionStatus.FAILED); + return this.rollback(handlerTransactions, e); + } + + + dataBroker.getFinishedTransactionsCount().getAndIncrement(); + transaction.changeStatus(TransactionStatus.COMMITED); + + log.trace("Transaction: {} Finished successfully.", transactionId); + + captureFinalState(listeners); + + log.trace("Transaction: {} Notifying listeners."); + + publishDataChangeEvent(listeners); + return Rpcs. getRpcResult(true, TransactionStatus.COMMITED, + Collections. emptySet()); + } + + private void captureInitialState(ImmutableList> listeners) { + for (ListenerStateCapture state : listeners) { + state.setInitialConfigurationState(dataBroker.readConfigurationData(state.getPath())); + state.setInitialOperationalState(dataBroker.readOperationalData(state.getPath())); + } + } + + + private void captureFinalState(ImmutableList> listeners) { + for (ListenerStateCapture state : listeners) { + state.setFinalConfigurationState(dataBroker.readConfigurationData(state.getPath())); + state.setFinalOperationalState(dataBroker.readOperationalData(state.getPath())); + } + } + + private void filterProbablyAffectedListeners( + ImmutableList> probablyAffectedListeners, Builder> reallyAffected) { + + for(ListenerStateCapture listenerSet : probablyAffectedListeners) { + P affectedPath = listenerSet.getPath(); + Optional> configChange = resolveConfigChange(affectedPath); + Optional> operChange = resolveOperChange(affectedPath); + + if(configChange.isPresent() || operChange.isPresent()) { + reallyAffected.add(listenerSet); + if(configChange.isPresent()) { + listenerSet.setNormalizedConfigurationChanges(configChange.get()); + } + + if(operChange.isPresent()) { + listenerSet.setNormalizedOperationalChanges(operChange.get()); + } + } + } + } + + private Optional> resolveOperChange(P affectedPath) { + Map originalOper = dataBroker.deepGetBySubpath(transaction.getOriginalOperationalData(),affectedPath); + Map createdOper = dataBroker.deepGetBySubpath(transaction.getCreatedOperationalData(),affectedPath); + Map updatedOper = dataBroker.deepGetBySubpath(transaction.getUpdatedOperationalData(),affectedPath); + Set

removedOper = Sets.filter(transaction.getRemovedOperationalData(), dataBroker.createIsContainedPredicate(affectedPath)); + return resolveChanges(affectedPath,originalOper,createdOper,updatedOper,removedOper); + } + + private Optional> resolveConfigChange(P affectedPath) { + Map originalConfig = dataBroker.deepGetBySubpath(transaction.getOriginalConfigurationData(),affectedPath); + Map createdConfig = dataBroker.deepGetBySubpath(transaction.getCreatedConfigurationData(),affectedPath); + Map updatedConfig = dataBroker.deepGetBySubpath(transaction.getUpdatedConfigurationData(),affectedPath); + Set

removedConfig = Sets.filter(transaction.getRemovedConfigurationData(), dataBroker.createIsContainedPredicate(affectedPath)); + return resolveChanges(affectedPath,originalConfig,createdConfig,updatedConfig,removedConfig); + } + + private Optional> resolveChanges(P affectedPath, Map originalConfig, Map createdConfig, Map updatedConfig,Set

potentialDeletions) { + Predicate

isContained = dataBroker.createIsContainedPredicate(affectedPath); + + if(createdConfig.isEmpty() && updatedConfig.isEmpty() && potentialDeletions.isEmpty()) { + return Optional.absent(); + } + RootedChangeSet changeSet = new RootedChangeSet(affectedPath,originalConfig); + changeSet.addCreated(createdConfig); + + for(Entry entry : updatedConfig.entrySet()) { + if(originalConfig.containsKey(entry.getKey())) { + changeSet.addUpdated(entry); + } else { + changeSet.addCreated(entry); + } + } + + for(Entry entry : originalConfig.entrySet()) { + for(P deletion : potentialDeletions) { + if(isContained.apply(deletion)) { + changeSet.addRemoval(entry.getKey()); + } + } + } + + if(changeSet.isChange()) { + return Optional.of(changeSet); + } else { + return Optional.absent(); + } + + } + + public void publishDataChangeEvent(final ImmutableList> listeners) { + ExecutorService executor = this.dataBroker.getExecutor(); + final Runnable notifyTask = new Runnable() { + @Override + public void run() { + for (final ListenerStateCapture listenerSet : listeners) { + { + DataChangeEvent changeEvent = listenerSet.createEvent(transaction); + for (final DataChangeListenerRegistration listener : listenerSet.getListeners()) { + try { + listener.getInstance().onDataChanged(changeEvent); + } catch (Exception e) { + log.error("Unhandled exception when invoking listener {}", listener); + } + } + } + } + } + }; + executor.submit(notifyTask); + } + + public RpcResult rollback(final List> transactions, final Exception e) { + for (final DataCommitTransaction transaction : transactions) { + transaction.rollback(); + } + Set _emptySet = Collections. emptySet(); + return Rpcs. getRpcResult(false, TransactionStatus.FAILED, _emptySet); + } +} diff --git a/opendaylight/md-sal/sal-common-util/pom.xml b/opendaylight/md-sal/sal-common-util/pom.xml index 3a9b00dce0..d3514ecc69 100644 --- a/opendaylight/md-sal/sal-common-util/pom.xml +++ b/opendaylight/md-sal/sal-common-util/pom.xml @@ -29,7 +29,6 @@ org.opendaylight.controller sal-common-api - ${project.version} diff --git a/opendaylight/md-sal/sal-connector-api/pom.xml b/opendaylight/md-sal/sal-connector-api/pom.xml index f28057e8a6..14733bc6b5 100644 --- a/opendaylight/md-sal/sal-connector-api/pom.xml +++ b/opendaylight/md-sal/sal-connector-api/pom.xml @@ -17,7 +17,6 @@ org.opendaylight.controller sal-core-api - 1.1-SNAPSHOT org.opendaylight.yangtools diff --git a/opendaylight/md-sal/sal-dom-api/pom.xml b/opendaylight/md-sal/sal-dom-api/pom.xml index d7b0296ce1..9c253eecb8 100644 --- a/opendaylight/md-sal/sal-dom-api/pom.xml +++ b/opendaylight/md-sal/sal-dom-api/pom.xml @@ -89,13 +89,10 @@ org.opendaylight.controller sal-common - 1.1-SNAPSHOT - org.opendaylight.controller config-api - 0.2.4-SNAPSHOT org.opendaylight.yangtools @@ -104,7 +101,6 @@ org.opendaylight.controller sal-common-api - ${project.version} org.opendaylight.yangtools @@ -113,7 +109,6 @@ org.osgi org.osgi.core - 5.0.0 bundle 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 24cb99f8c3..8a9d167865 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 @@ -14,7 +14,7 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -public interface RpcProvisionRegistry extends BrokerService, RouteChangePublisher { +public interface RpcProvisionRegistry extends RpcImplementation, BrokerService, RouteChangePublisher { /** * Registers an implementation of the rpc. diff --git a/opendaylight/md-sal/sal-dom-broker/pom.xml b/opendaylight/md-sal/sal-dom-broker/pom.xml index 8b193e03aa..d22b54ee19 100644 --- a/opendaylight/md-sal/sal-dom-broker/pom.xml +++ b/opendaylight/md-sal/sal-dom-broker/pom.xml @@ -18,22 +18,18 @@ org.opendaylight.controller sal-core-api - 1.1-SNAPSHOT org.opendaylight.controller sal-common-util - 1.1-SNAPSHOT org.opendaylight.controller sal-common-impl - 1.1-SNAPSHOT org.opendaylight.controller sal-core-spi - 1.1-SNAPSHOT org.slf4j @@ -50,7 +46,6 @@ org.opendaylight.controller config-api - 0.2.4-SNAPSHOT org.opendaylight.yangtools @@ -64,6 +59,7 @@ + org.opendaylight.yangtools yang-maven-plugin 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 aa5138a04d..8f734d7d4c 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 @@ -73,7 +73,7 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable { return session; } - protected def Future> invokeRpc(QName rpc, CompositeNode input) { + protected def Future> invokeRpcAsync(QName rpc, CompositeNode input) { val result = executor.submit([|router.invokeRpc(rpc, input)] as Callable>); return result; } @@ -135,5 +135,13 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable { override > registerRouteChangeListener(L listener) { return router.registerRouteChangeListener(listener); } + + override invokeRpc(QName rpc,CompositeNode input){ + return router.invokeRpc(rpc,input) + } + + override getSupportedRpcs() { + return router.getSupportedRpcs(); + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend index e4808e9bd6..813f52b67d 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend @@ -37,7 +37,7 @@ class ConsumerContextImpl implements ConsumerSession { } override rpc(QName rpc, CompositeNode input) { - return broker.invokeRpc(rpc, input); + return broker.invokeRpcAsync(rpc, input); } override T getService(Class service) { 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 5a3e060a3c..a8bdddb510 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 @@ -219,4 +219,6 @@ public class MountPointImpl implements MountProvisionInstance, SchemaContextProv L listener) { return rpcs.registerRouteChangeListener(listener); } + + } 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 b32d906d1e..b02a37c300 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 @@ -30,6 +30,7 @@ import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; 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,6 +42,7 @@ import com.google.common.collect.ImmutableSet; public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator implements // DataStore, // SchemaServiceListener, // + SchemaContextListener, // AutoCloseable { private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class); 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 e375e14cf2..e218a95782 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 @@ -16,9 +16,13 @@ import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; import org.opendaylight.controller.sal.core.api.RpcRoutingContext; import org.opendaylight.yangtools.concepts.ListenerRegistration; 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.ServiceReference; +import java.util.Set; + public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy implements RpcProvisionRegistry { @@ -45,4 +49,15 @@ public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy> ListenerRegistration registerRouteChangeListener(L listener) { return getDelegate().registerRouteChangeListener(listener); } + + + @Override + public Set getSupportedRpcs() { + return getDelegate().getSupportedRpcs(); + } + + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode input) { + return getDelegate().invokeRpc(rpc,input); + } } diff --git a/opendaylight/md-sal/sal-dom-spi/pom.xml b/opendaylight/md-sal/sal-dom-spi/pom.xml index 8aa2a006f6..e007ee7429 100644 --- a/opendaylight/md-sal/sal-dom-spi/pom.xml +++ b/opendaylight/md-sal/sal-dom-spi/pom.xml @@ -17,7 +17,6 @@ org.opendaylight.controller sal-core-api - 1.1-SNAPSHOT bundle diff --git a/opendaylight/md-sal/sal-netconf-connector/pom.xml b/opendaylight/md-sal/sal-netconf-connector/pom.xml index 597b02ebb5..b060ca42d0 100644 --- a/opendaylight/md-sal/sal-netconf-connector/pom.xml +++ b/opendaylight/md-sal/sal-netconf-connector/pom.xml @@ -33,7 +33,6 @@ org.opendaylight.controller netty-threadgroup-config - 0.2.4-SNAPSHOT org.opendaylight.controller @@ -146,7 +145,6 @@ org.opendaylight.controller logback-config test - ${netconf.version} org.mockito @@ -160,35 +158,29 @@ org.opendaylight.controller sal-binding-broker-impl - 1.1-SNAPSHOT test org.opendaylight.controller sal-binding-broker-impl - 1.1-SNAPSHOT test-jar test org.opendaylight.controller ietf-netconf-monitoring - 0.2.4-SNAPSHOT org.opendaylight.yangtools.model ietf-inet-types - 2010.09.24.3 org.opendaylight.controller threadpool-config-api - 0.2.4-SNAPSHOT org.opendaylight.controller netty-config-api - 0.2.4-SNAPSHOT diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceTwoPhaseCommitTransaction.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceTwoPhaseCommitTransaction.java index c16ee170de..c5390e5409 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceTwoPhaseCommitTransaction.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceTwoPhaseCommitTransaction.java @@ -7,11 +7,11 @@ */ package org.opendaylight.controller.sal.connect.netconf; -import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_ACTION_QNAME; import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_CANDIDATE_QNAME; import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_COMMIT_QNAME; import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_CONFIG_QNAME; import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_EDIT_CONFIG_QNAME; +import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_OPERATION_QNAME; import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_RUNNING_QNAME; import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_TARGET_QNAME; @@ -52,7 +52,7 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac public void prepare() { for (InstanceIdentifier toRemove : modification.getRemovedConfigurationData()) { - sendRemove(toRemove); + sendDelete(toRemove); } for(Entry toUpdate : modification.getUpdatedConfigurationData().entrySet()) { sendMerge(toUpdate.getKey(),toUpdate.getValue()); @@ -64,8 +64,8 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac sendEditRpc(createEditStructure(key, Optional.absent(), Optional.of(value))); } - private void sendRemove(InstanceIdentifier toRemove) { - sendEditRpc(createEditStructure(toRemove, Optional.of("remove"), Optional. absent())); + private void sendDelete(InstanceIdentifier toDelete) { + sendEditRpc(createEditStructure(toDelete, Optional.of("delete"), Optional. absent())); } private void sendEditRpc(CompositeNode editStructure) { @@ -92,7 +92,7 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac return ret; } - private CompositeNode createEditStructure(InstanceIdentifier dataPath, Optional action, + private CompositeNode createEditStructure(InstanceIdentifier dataPath, Optional operation, Optional lastChildOverride) { List path = dataPath.getPath(); List reversed = Lists.reverse(path); @@ -110,8 +110,8 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac } if (isLast) { - if (action.isPresent()) { - builder.setAttribute(NETCONF_ACTION_QNAME, action.get()); + if (operation.isPresent()) { + builder.setAttribute(NETCONF_OPERATION_QNAME, operation.get()); } if (lastChildOverride.isPresent()) { List> children = lastChildOverride.get().getChildren(); @@ -132,7 +132,7 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac } @Override - public RpcResult finish() throws IllegalStateException { + public RpcResult finish() { CompositeNodeBuilder commitInput = ImmutableCompositeNode.builder(); commitInput.setQName(NETCONF_COMMIT_QNAME); RpcResult rpcResult = device.invokeRpc(NetconfMapping.NETCONF_COMMIT_QNAME, commitInput.toInstance()); diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfMapping.xtend b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfMapping.xtend index 53ed49cd2a..f409ecdade 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfMapping.xtend +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfMapping.xtend @@ -16,24 +16,30 @@ import java.util.Collections import java.util.List import java.util.Set import java.util.concurrent.atomic.AtomicInteger -import org.opendaylight.controller.netconf.api.NetconfMessage import org.opendaylight.controller.sal.common.util.Rpcs -import org.opendaylight.yangtools.yang.common.QName -import org.opendaylight.yangtools.yang.common.RpcResult import org.opendaylight.yangtools.yang.data.api.CompositeNode import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument -import org.opendaylight.yangtools.yang.data.api.Node import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode -import org.opendaylight.yangtools.yang.data.impl.NodeUtils -import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl +import java.util.Collections +import java.util.List +import java.util.Set +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument +import org.opendaylight.yangtools.yang.data.api.Node +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils import org.opendaylight.yangtools.yang.model.api.NotificationDefinition import org.opendaylight.yangtools.yang.model.api.SchemaContext import org.w3c.dom.Document import org.w3c.dom.Element +import org.opendaylight.yangtools.yang.common.QName +import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl +import org.opendaylight.controller.netconf.api.NetconfMessage +import org.opendaylight.yangtools.yang.common.RpcResult class NetconfMapping { @@ -50,7 +56,7 @@ class NetconfMapping { public static val NETCONF_GET_CONFIG_QNAME = QName.create(NETCONF_QNAME, "get-config"); public static val NETCONF_EDIT_CONFIG_QNAME = QName.create(NETCONF_QNAME, "edit-config"); public static val NETCONF_DELETE_CONFIG_QNAME = QName.create(NETCONF_QNAME, "delete-config"); - public static val NETCONF_ACTION_QNAME = QName.create(NETCONF_QNAME, "action"); + public static val NETCONF_OPERATION_QNAME = QName.create(NETCONF_QNAME, "operation"); public static val NETCONF_COMMIT_QNAME = QName.create(NETCONF_QNAME, "commit"); public static val NETCONF_CONFIG_QNAME = QName.create(NETCONF_QNAME, "config"); @@ -92,6 +98,9 @@ class NetconfMapping { for (arg : argument.keyValues.entrySet) { list.add = new SimpleNodeTOImpl(arg.key, null, arg.value); } + if (node != null) { + list.add(node); + } return new CompositeNodeTOImpl(argument.nodeType, null, list) } @@ -120,9 +129,9 @@ class NetconfMapping { } static def NetconfMessage toRpcMessage(QName rpc, CompositeNode node,Optional ctx) { - val rpcPayload = wrap(NETCONF_RPC_QNAME, flattenInput(node)); - val w3cPayload = NodeUtils.buildShadowDomTree(rpcPayload); - w3cPayload.documentElement.setAttribute("message-id", "m-" + messageId.andIncrement); + val rpcPayload = wrap(NETCONF_RPC_QNAME, flattenInput(node)) + val w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, XmlDocumentUtils.defaultValueCodecProvider) + w3cPayload.documentElement.setAttribute("message-id", "m-" + messageId.andIncrement) return new NetconfMessage(w3cPayload); } diff --git a/opendaylight/md-sal/sal-remote/pom.xml b/opendaylight/md-sal/sal-remote/pom.xml index b6d0632068..d4f5d43e5e 100644 --- a/opendaylight/md-sal/sal-remote/pom.xml +++ b/opendaylight/md-sal/sal-remote/pom.xml @@ -6,13 +6,20 @@ 1.1-SNAPSHOT sal-remote - jar + bundle scm:git:ssh://git.opendaylight.org:29418/controller.git scm:git:ssh://git.opendaylight.org:29418/controller.git https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL HEAD + + + org.opendaylight.controller + sal-binding-api + 1.1-SNAPSHOT + + @@ -80,12 +87,4 @@ - - - - org.opendaylight.controller - sal-binding-api - 1.1-SNAPSHOT - - diff --git a/opendaylight/md-sal/sal-remote/src/main/java/org/opendaylight/controller/sal/restconf/service/impl/SalRemoteServiceImpl.java b/opendaylight/md-sal/sal-remote/src/main/java/org/opendaylight/controller/sal/restconf/service/impl/SalRemoteServiceImpl.java deleted file mode 100644 index 1da603266b..0000000000 --- a/opendaylight/md-sal/sal-remote/src/main/java/org/opendaylight/controller/sal/restconf/service/impl/SalRemoteServiceImpl.java +++ /dev/null @@ -1,34 +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.restconf.service.impl; - -import java.util.concurrent.Future; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.BeginTransactionOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionInput; -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.CreateNotificationStreamInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService; -import org.opendaylight.yangtools.yang.common.RpcResult; - -public class SalRemoteServiceImpl implements SalRemoteService { - @Override - public Future> beginTransaction() { - return null; - } - - @Override - public Future> createDataChangeEventSubscription(CreateDataChangeEventSubscriptionInput input) { - return null; - } - - @Override - public Future> createNotificationStream(CreateNotificationStreamInput input) { - return null; - } -} diff --git a/opendaylight/md-sal/sal-rest-connector/pom.xml b/opendaylight/md-sal/sal-rest-connector/pom.xml index a4d2f4ca25..cc3b0296ed 100644 --- a/opendaylight/md-sal/sal-rest-connector/pom.xml +++ b/opendaylight/md-sal/sal-rest-connector/pom.xml @@ -48,7 +48,6 @@ com.google.code.gson gson - 2.2.4 org.opendaylight.yangtools @@ -57,7 +56,6 @@ io.netty netty-codec-http - 4.0.10.Final @@ -74,7 +72,6 @@ ch.qos.logback logback-classic - 1.0.9 test diff --git a/opendaylight/md-sal/sal-restconf-broker/pom.xml b/opendaylight/md-sal/sal-restconf-broker/pom.xml index 8294c101e9..2fe625ffb3 100644 --- a/opendaylight/md-sal/sal-restconf-broker/pom.xml +++ b/opendaylight/md-sal/sal-restconf-broker/pom.xml @@ -6,47 +6,85 @@ 1.1-SNAPSHOT sal-restconf-broker - jar + bundle scm:git:ssh://git.opendaylight.org:29418/controller.git scm:git:ssh://git.opendaylight.org:29418/controller.git https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL HEAD - - - - org.apache.felix - maven-bundle-plugin - true - - - - org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT + + + org.opendaylight.controller + sal-binding-util org.opendaylight.controller sal-remote - 1.1-SNAPSHOT + + + org.opendaylight.controller + sal-broker-impl + + + org.opendaylight.controller + sal-binding-config org.opendaylight.controller sal-core-api - 1.1-SNAPSHOT org.opendaylight.yangtools restconf-client-api - ${yangtools.version} + + + org.opendaylight.yangtools + restconf-client-impl org.slf4j slf4j-api + + + + org.apache.felix + maven-bundle-plugin + true + + + ${project.groupId}.${project.artifactId} + + * + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/ + + + + + + + diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.java deleted file mode 100644 index 76c98e3dda..0000000000 --- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.java +++ /dev/null @@ -1,47 +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.binding.impl; - -import org.opendaylight.controller.sal.binding.api.NotificationListener; -import org.opendaylight.controller.sal.binding.api.NotificationService; -import org.opendaylight.yangtools.concepts.Registration; -import org.opendaylight.yangtools.yang.binding.Notification; - -public class NotificationServiceImpl implements NotificationService { - @Override - public void addNotificationListener(Class notificationType, NotificationListener listener) { - - } - - @Override - public void addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - - } - - @Override - public void removeNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - - } - - @Override - public void removeNotificationListener(Class notificationType, NotificationListener listener) { - - } - - @Override - public Registration> registerNotificationListener(Class notificationType, NotificationListener listener) { - //TODO implementation using sal-remote - return null; - } - - @Override - public Registration registerNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - //TODO implementation using sal-remote - return null; - } -} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java similarity index 98% rename from opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerServiceImpl.java rename to opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java index ad28305b22..6fe56c87ed 100644 --- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerServiceImpl.java +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.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.sal.binding.impl; +package org.opendaylight.controller.sal.restconf.binding.impl; import java.net.URL; import java.util.concurrent.Future; diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java index 988bfd8ca5..74b23201e7 100644 --- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java @@ -8,25 +8,60 @@ package org.opendaylight.controller.sal.restconf.broker; -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 com.google.common.collect.ImmutableClassToInstanceMap; +import org.opendaylight.controller.md.sal.binding.util.BindingContextUtils; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; +import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; +import org.opendaylight.controller.sal.binding.api.BindingAwareService; +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.restconf.broker.impl.RemoteServicesFactory; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; import org.osgi.framework.BundleContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static com.google.common.base.Preconditions.checkState; -public class SalRemoteServiceBroker implements Broker,AutoCloseable { +public class SalRemoteServiceBroker implements BindingAwareBroker,AutoCloseable { - @Override - public void close() throws Exception { + private static final Logger logger = LoggerFactory.getLogger(SalRemoteServiceBroker.class.toString()); + private ImmutableClassToInstanceMap supportedConsumerServices; + + private final String identifier; + + private RpcConsumerRegistry rpcBroker; + private NotificationService notificationBroker; + private DataBrokerService dataBroker; + private final RemoteServicesFactory servicesFactory; + + public SalRemoteServiceBroker(String instanceName,RestconfClientContext clientContext){ + this.identifier = instanceName; + this.servicesFactory = new RemoteServicesFactory(clientContext); } - @Override - public ConsumerSession registerConsumer(Consumer cons, BundleContext context) { - return null; + public void start() { + logger.info("Starting Binding Aware Broker: {}", identifier); + + supportedConsumerServices = ImmutableClassToInstanceMap. builder() + .put(NotificationService.class, servicesFactory.getNotificationService()) // + .put(DataBrokerService.class,servicesFactory.getDataBrokerService() ) // + .put(RpcConsumerRegistry.class,servicesFactory.getRpcConsumerRegistry() ).build(); } + public ProviderContext registerProvider(BindingAwareProvider provider, BundleContext ctx) { + throw new UnsupportedOperationException(); + } + @Override + public void close() throws Exception { + //TODO decide if serviceFactory should close clientContext or it has to be closed by consumer + } @Override - public ProviderSession registerProvider(Provider prov, BundleContext context) { - return null; + public ConsumerContext registerConsumer(BindingAwareConsumer consumer, BundleContext ctx) { + checkState(supportedConsumerServices != null, "Broker is not initialized."); + return BindingContextUtils.createConsumerContextAndInitialize(consumer, supportedConsumerServices); } + } diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/event/RemoteDataChangeEvent.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/event/RemoteDataChangeEvent.java new file mode 100644 index 0000000000..9dfd262da2 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/event/RemoteDataChangeEvent.java @@ -0,0 +1,144 @@ +/* + * 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.restconf.broker.event; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.annotation.concurrent.ThreadSafe; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.DataChangedNotification; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +@ThreadSafe +public class RemoteDataChangeEvent implements DataChangeEvent,DataObject> { + private final Map, DataObject> createdConfig, createdOper, origConfig, origOper, updatedConfig, updatedOper; + private final Set> removedConfig, removedOper; + + public RemoteDataChangeEvent(DataChangedNotification dataChangedNotification) { + final Map, DataObject> createdConfig = new HashMap<>(); + final Map, DataObject> createdOper = new HashMap<>(); + final Map, DataObject> origConfig = new HashMap<>(); + final Map, DataObject> origOper = new HashMap<>(); + final Map, DataObject> updatedConfig = new HashMap<>(); + final Map, DataObject> updatedOper = new HashMap<>(); + final Set> removedConfig = new HashSet<>(); + final Set> removedOper = new HashSet<>(); + + for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()) { + switch (d.getOperation()) { + case Created: + switch (d.getStore()) { + case Config: + createdConfig.put(d.getPath(), d); + break; + case Operation: + createdOper.put(d.getPath(), d); + break; + } + break; + case Deleted: + switch (d.getStore()) { + case Config: + removedConfig.add(d.getPath()); + break; + case Operation: + removedOper.add(d.getPath()); + break; + } + break; + case Updated: + switch (d.getStore()) { + case Config: + origConfig.put(d.getPath(), d); + updatedConfig.put(d.getPath(), d); + break; + case Operation: + origOper.put(d.getPath(),d); + updatedOper.put(d.getPath(),d); + break; + } + break; + } + } + + this.createdConfig = Collections.unmodifiableMap(createdConfig); + this.createdOper = Collections.unmodifiableMap(createdOper); + this.origConfig = Collections.unmodifiableMap(origConfig); + this.origOper = Collections.unmodifiableMap(origOper); + this.updatedConfig = Collections.unmodifiableMap(updatedConfig); + this.updatedOper = Collections.unmodifiableMap(updatedOper); + this.removedConfig = Collections.unmodifiableSet(removedConfig); + this.removedOper = Collections.unmodifiableSet(removedOper); + } + + @Override + public DataObject getOriginalConfigurationSubtree() { + throw new UnsupportedOperationException(); + } + + @Override + public DataObject getOriginalOperationalSubtree() { + throw new UnsupportedOperationException(); + } + + @Override + public DataObject getUpdatedConfigurationSubtree() { + throw new UnsupportedOperationException(); + } + + @Override + public DataObject getUpdatedOperationalSubtree() { + throw new UnsupportedOperationException(); + } + + @Override + public Map, DataObject> getCreatedOperationalData() { + return createdOper; + } + + @Override + public Map, DataObject> getCreatedConfigurationData() { + return createdConfig; + } + + @Override + public Map, DataObject> getUpdatedOperationalData() { + return updatedOper; + } + + @Override + public Map, DataObject> getUpdatedConfigurationData() { + return updatedConfig; + } + + @Override + public Set> getRemovedConfigurationData() { + return removedConfig; + } + + @Override + public Set> getRemovedOperationalData() { + return removedOper; + } + + @Override + public Map, DataObject> getOriginalConfigurationData() { + return origConfig; + } + + @Override + public Map, DataObject> getOriginalOperationalData() { + return origOper; + } +} 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 new file mode 100644 index 0000000000..e6659c2265 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java @@ -0,0 +1,168 @@ +/* + * 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.restconf.broker.impl; + +import com.google.common.base.Optional; +import java.util.Map; +import java.util.concurrent.ExecutionException; +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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.BeginTransactionOutput; +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.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; +import org.slf4j.LoggerFactory; + +public class DataBrokerServiceImpl implements DataBrokerService { + + private static final Logger logger = LoggerFactory.getLogger(DataBrokerServiceImpl.class.toString()); + private RestconfClientContext restconfClientContext; + private SalRemoteService salRemoteService; + + public DataBrokerServiceImpl(RestconfClientContext restconfClientContext) { + 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() { + Future> rpcResultFuture = this.salRemoteService.beginTransaction(); + //TODO finish yang model for proper remoteDataModificationTransaction setup + RemoteDataModificationTransaction remoteDataModificationTransaction = new RemoteDataModificationTransaction(); + 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 { + Optional optDataObject = (Optional) this.restconfClientContext.getConfigurationDatastore().readData(path).get(); + if (optDataObject.isPresent()){ + return optDataObject.get(); + } + } catch (InterruptedException e) { + logger.trace("Reading configuration data interrupted {}",e); + } catch (ExecutionException e) { + logger.trace("Reading configuration execution exception {}",e); + } + throw new IllegalStateException("No data to return."); + } + + @Override + public DataObject readOperationalData(InstanceIdentifier path) { + try { + Optional optDataObject = (Optional) this.restconfClientContext.getOperationalDatastore().readData(path).get(); + if (optDataObject.isPresent()){ + return optDataObject.get(); + } + } catch (InterruptedException e) { + logger.trace("Reading configuration data interrupted {}",e); + } catch (ExecutionException e) { + logger.trace("Reading configuration execution exception {}",e); + } + throw new IllegalStateException("No data to return."); + } + @Override + public ListenerRegistration registerDataChangeListener(InstanceIdentifier path, DataChangeListener listener) { + CreateDataChangeEventSubscriptionInputBuilder inputBuilder = new CreateDataChangeEventSubscriptionInputBuilder(); + Future> rpcResultFuture = salRemoteService.createDataChangeEventSubscription(inputBuilder.setPath(path).build()); + String streamName = ""; + try { + if (rpcResultFuture.get().isSuccessful()){ + streamName = rpcResultFuture.get().getResult().getStreamName(); + } + } catch (InterruptedException e) { + logger.trace("Interupted while getting rpc result due to {}",e); + } catch (ExecutionException e) { + logger.trace("Execution exception while getting rpc result due to {}",e); + } + 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 DataChangeListener dataChangeListener; + public SalRemoteDataListenerRegistration(DataChangeListener dataChangeListener){ + this.dataChangeListener = dataChangeListener; + } + @Override + public DataChangeListener getInstance() { + return this.dataChangeListener; + } + @Override + public void close() throws Exception { + //noop + } + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/NotificationServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/NotificationServiceImpl.java new file mode 100644 index 0000000000..3272ce5670 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/NotificationServiceImpl.java @@ -0,0 +1,118 @@ +/* + * 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.restconf.broker.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; + +import org.opendaylight.controller.sal.binding.api.NotificationListener; +import org.opendaylight.controller.sal.binding.api.NotificationService; +import org.opendaylight.controller.sal.restconf.broker.listeners.RemoteNotificationListener; +import org.opendaylight.controller.sal.restconf.broker.tools.RemoteStreamTools; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.QName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; +import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo; +import org.opendaylight.yangtools.yang.binding.Notification; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import com.google.common.collect.SetMultimap; + +public class NotificationServiceImpl implements NotificationService { + private final SalRemoteService salRemoteService; + private final RestconfClientContext restconfClientContext; + + private final Multimap,NotificationListener> listeners; + private ExecutorService _executor; + + public NotificationServiceImpl(RestconfClientContext restconfClienetContext){ + this.restconfClientContext = restconfClienetContext; + this.salRemoteService = this.restconfClientContext.getRpcServiceContext(SalRemoteService.class).getRpcService(); + + HashMultimap,NotificationListener> _create = HashMultimap., NotificationListener>create(); + SetMultimap,NotificationListener> _synchronizedSetMultimap = Multimaps., NotificationListener>synchronizedSetMultimap(_create); + this.listeners = _synchronizedSetMultimap; + + } + public ExecutorService getExecutor() { + return this._executor; + } + + public void setExecutor(final ExecutorService executor) { + this._executor = executor; + } + + @Override + public void addNotificationListener(Class notificationType, NotificationListener listener) { + this.listeners.put(notificationType, listener); + } + + @Override + public void addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { + UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException("Deprecated method. Use registerNotificationListener instead."); + throw _unsupportedOperationException; + } + + @Override + public void removeNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { + UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException( + "Deprecated method. Use RegisterNotificationListener returned value to close registration."); + throw _unsupportedOperationException; + } + + @Override + public void removeNotificationListener(Class notificationType, NotificationListener listener) { + this.listeners.remove(notificationType, listener); + } + + @Override + public Registration> registerNotificationListener(Class notificationType, NotificationListener listener) { + //TODO implementation using sal-remote + List notifications = new ArrayList(); + notifications.add(new QName(notificationType.toString())); + String notificationStreamName = RemoteStreamTools.createNotificationStream(salRemoteService, notifications); + final Map desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext, notificationStreamName); + RemoteNotificationListener remoteNotificationListener = new RemoteNotificationListener(listener); + ListenerRegistration listenerRegistration = restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(remoteNotificationListener); + return new SalNotificationRegistration(listenerRegistration); + } + + @Override + public Registration registerNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { + //TODO implementation using sal-remote + String notificationStreamName = RemoteStreamTools.createNotificationStream(salRemoteService, null); + final Map desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext, notificationStreamName); + return restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(listener); + } + + private class SalNotificationRegistration implements Registration>{ + private final Registration registration; + + public SalNotificationRegistration(ListenerRegistration listenerRegistration){ + this.registration = listenerRegistration; + } + + @Override + public NotificationListener getInstance() { + return this.getInstance(); + } + + @Override + public void close() throws Exception { + this.registration.close(); + } + } + + +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RemoteServicesFactory.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RemoteServicesFactory.java new file mode 100644 index 0000000000..65ecd8b70b --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RemoteServicesFactory.java @@ -0,0 +1,35 @@ +/* + * 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.restconf.broker.impl; + +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.yangtools.restconf.client.api.RestconfClientContext; + +public class RemoteServicesFactory { + + private final RestconfClientContext restconfClientContext; + + public RemoteServicesFactory(RestconfClientContext restconfClientContext){ + this.restconfClientContext = restconfClientContext; + } + + public DataBrokerService getDataBrokerService(){ + return new DataBrokerServiceImpl(this.restconfClientContext); + } + + public NotificationService getNotificationService(){ + return new NotificationServiceImpl(this.restconfClientContext); + } + + public RpcConsumerRegistry getRpcConsumerRegistry(){ + return new RpcConsumerRegistryImpl(this.restconfClientContext); + } + +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcConsumerRegistryImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RpcConsumerRegistryImpl.java similarity index 58% rename from opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcConsumerRegistryImpl.java rename to opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RpcConsumerRegistryImpl.java index e6a67ee8eb..82342ace26 100644 --- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcConsumerRegistryImpl.java +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RpcConsumerRegistryImpl.java @@ -5,15 +5,21 @@ * 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; +package org.opendaylight.controller.sal.restconf.broker.impl; import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; import org.opendaylight.yangtools.yang.binding.RpcService; public class RpcConsumerRegistryImpl implements RpcConsumerRegistry { + + private RestconfClientContext restconfClientContext; + + public RpcConsumerRegistryImpl(RestconfClientContext restconfClientContext){ + this.restconfClientContext = restconfClientContext; + } @Override public T getRpcService(Class module) { - //TODO implementation using restconf-client - return null; + return restconfClientContext.getRpcServiceContext(module).getRpcService(); } } diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteDataChangeNotificationListener.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteDataChangeNotificationListener.java new file mode 100644 index 0000000000..df72ac8ce2 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteDataChangeNotificationListener.java @@ -0,0 +1,27 @@ +/* + * 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.restconf.broker.listeners; + +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.controller.sal.restconf.broker.event.RemoteDataChangeEvent; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.DataChangedNotification; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteListener; + +public class RemoteDataChangeNotificationListener implements SalRemoteListener { + + + private final DataChangeListener dataChangeListener; + + public RemoteDataChangeNotificationListener(DataChangeListener dataChangeListener){ + this.dataChangeListener = dataChangeListener; + } + @Override + public void onDataChangedNotification(DataChangedNotification notification) { + this.dataChangeListener.onDataChanged(new RemoteDataChangeEvent(notification)); + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteNotificationListener.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteNotificationListener.java new file mode 100644 index 0000000000..895a5030e9 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteNotificationListener.java @@ -0,0 +1,23 @@ +/* + * 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.restconf.broker.listeners; + +import org.opendaylight.controller.sal.binding.api.NotificationListener; + +public class RemoteNotificationListener implements org.opendaylight.yangtools.yang.binding.NotificationListener { + + org.opendaylight.controller.sal.binding.api.NotificationListener listener; + + public RemoteNotificationListener(NotificationListener listener){ + this.listener = listener; + } + public NotificationListener getListener(){ + return this.listener; + } + +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/SalNotificationListener.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/SalNotificationListener.java new file mode 100644 index 0000000000..16ca0aee93 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/SalNotificationListener.java @@ -0,0 +1,24 @@ +/* + * 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.restconf.broker.listeners; + +import org.opendaylight.controller.sal.binding.api.NotificationListener; +import org.opendaylight.yangtools.yang.binding.Notification; + + +public class SalNotificationListener implements NotificationListener { + private NotificationListener notificationListener; + + public SalNotificationListener( NotificationListener notificationListener){ + this.notificationListener = notificationListener; + } + @Override + public void onNotification(Notification notification) { + this.notificationListener.onNotification(notification); + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/tools/RemoteStreamTools.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/tools/RemoteStreamTools.java new file mode 100644 index 0000000000..726f7f0649 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/tools/RemoteStreamTools.java @@ -0,0 +1,71 @@ +/* + * 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.restconf.broker.tools; + +import com.google.common.util.concurrent.ListenableFuture; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.QName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; +import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RemoteStreamTools { + private static final Logger logger = LoggerFactory.getLogger(RemoteStreamTools.class.toString()); + + public static String createNotificationStream(SalRemoteService salRemoteService,List notifications){ + CreateNotificationStreamInputBuilder notificationStreamInputBuilder = new CreateNotificationStreamInputBuilder(); + + if (null == notifications){ + notificationStreamInputBuilder.setNotifications(notifications); + } + + Future> notificationStream = salRemoteService.createNotificationStream(notificationStreamInputBuilder.build()); + + String nofiticationStreamIdentifier = ""; + try { + if (notificationStream.get().isSuccessful()){ + nofiticationStreamIdentifier = notificationStream.get().getResult().getNotificationStreamIdentifier(); + } + } catch (InterruptedException e) { + logger.trace("Interrupted while resolving notification stream identifier due to {}",e); + } catch (ExecutionException e) { + logger.trace("Execution exception while resolving notification stream identifier due to {}",e); + } + return nofiticationStreamIdentifier; + } + + public static Map createEventStream(RestconfClientContext restconfClientContext, String desiredStreamName){ + ListenableFuture> availableEventStreams = restconfClientContext.getAvailableEventStreams(); + final Map desiredEventStream = new HashMap(); + + try { + Iterator it = availableEventStreams.get().iterator(); + while (it.hasNext()){ + if (it.next().getIdentifier().equals(desiredStreamName)){ + desiredEventStream.put(desiredStreamName,it.next()); + } + } + } catch (InterruptedException e) { + logger.trace("Resolving of event stream interrupted due to {}",e); + } catch (ExecutionException e) { + logger.trace("Resolving of event stream failed due to {}",e); + } + return desiredEventStream; + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/transactions/RemoteDataModificationTransaction.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/transactions/RemoteDataModificationTransaction.java new file mode 100644 index 0000000000..7f9cc8f6c4 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/transactions/RemoteDataModificationTransaction.java @@ -0,0 +1,122 @@ +/* + * 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.restconf.broker.transactions; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Future; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; + +public class RemoteDataModificationTransaction implements DataModificationTransaction { + //TODO implement this + + @Override + public Object getIdentifier() { + return null; + } + + @Override + public TransactionStatus getStatus() { + return null; + } + + @Override + public void putRuntimeData(InstanceIdentifier path, DataObject data) { + + } + + @Override + public void putOperationalData(InstanceIdentifier path, DataObject data) { + + } + + @Override + public void putConfigurationData(InstanceIdentifier path, DataObject data) { + + } + + @Override + public void removeRuntimeData(InstanceIdentifier path) { + + } + + @Override + public void removeOperationalData(InstanceIdentifier path) { + + } + + @Override + public void removeConfigurationData(InstanceIdentifier path) { + + } + + @Override + public Future> commit() { + return null; + } + + @Override + public ListenerRegistration registerListener(DataTransactionListener listener) { + return null; + } + + @Override + public Map, DataObject> getCreatedOperationalData() { + return null; + } + + @Override + public Map, DataObject> getCreatedConfigurationData() { + return null; + } + + @Override + public Map, DataObject> getUpdatedOperationalData() { + return null; + } + + @Override + public Map, DataObject> getUpdatedConfigurationData() { + return null; + } + + @Override + public Set> getRemovedConfigurationData() { + return null; + } + + @Override + public Set> getRemovedOperationalData() { + return null; + } + + @Override + public Map, DataObject> getOriginalConfigurationData() { + return null; + } + + @Override + public Map, DataObject> getOriginalOperationalData() { + return null; + } + + @Override + public DataObject readOperationalData(InstanceIdentifier path) { + return null; + } + + @Override + public DataObject readConfigurationData(InstanceIdentifier path) { + return null; + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/DataBrokerImplTest.java b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/DataBrokerImplTest.java new file mode 100644 index 0000000000..eafc47d620 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/DataBrokerImplTest.java @@ -0,0 +1,15 @@ +/* + * 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.binding.impl.test; + +public class DataBrokerImplTest { + + public static void main(String[] args){ + + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/NotificationServiceImplTest.java b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/NotificationServiceImplTest.java new file mode 100644 index 0000000000..a91b06ee76 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/NotificationServiceImplTest.java @@ -0,0 +1,15 @@ +/* + * 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.binding.impl.test; + +public class NotificationServiceImplTest { + + public static void main(String[] args){ + + } +} diff --git a/opendaylight/md-sal/samples/toaster-consumer/pom.xml b/opendaylight/md-sal/samples/toaster-consumer/pom.xml index ff09c1dbf0..40e99ec28b 100644 --- a/opendaylight/md-sal/samples/toaster-consumer/pom.xml +++ b/opendaylight/md-sal/samples/toaster-consumer/pom.xml @@ -39,7 +39,6 @@ org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT diff --git a/opendaylight/md-sal/samples/toaster-provider/pom.xml b/opendaylight/md-sal/samples/toaster-provider/pom.xml index 3f9ac737a2..ca1e3b4689 100644 --- a/opendaylight/md-sal/samples/toaster-provider/pom.xml +++ b/opendaylight/md-sal/samples/toaster-provider/pom.xml @@ -38,12 +38,10 @@ org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT org.opendaylight.controller sal-common-util - 1.1-SNAPSHOT diff --git a/opendaylight/md-sal/statistics-manager/pom.xml b/opendaylight/md-sal/statistics-manager/pom.xml index 5c3fc2329a..a9c1e05413 100644 --- a/opendaylight/md-sal/statistics-manager/pom.xml +++ b/opendaylight/md-sal/statistics-manager/pom.xml @@ -23,17 +23,14 @@ org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT org.opendaylight.controller.model model-flow-statistics - 1.1-SNAPSHOT org.opendaylight.controller.model model-flow-base - 1.1-SNAPSHOT org.eclipse.xtend diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java new file mode 100644 index 0000000000..4a58579b13 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java @@ -0,0 +1,48 @@ +/* + * 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.md.statistics.manager; + +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +abstract class AbstractListeningStatsTracker extends AbstractStatsTracker implements AutoCloseable, DataChangeListener { + private static final Logger logger = LoggerFactory.getLogger(AbstractListeningStatsTracker.class); + private ListenerRegistration reg; + + protected AbstractListeningStatsTracker(FlowCapableContext context, long lifetimeNanos) { + super(context, lifetimeNanos); + } + + protected abstract InstanceIdentifier listenPath(); + protected abstract String statName(); + + public void start(final DataBrokerService dbs) { + Preconditions.checkState(reg == null); + + reg = dbs.registerDataChangeListener(listenPath(), this); + logger.debug("{} Statistics tracker for node {} started", statName(), getNodeIdentifier()); + } + + @Override + public final void close() { + if (reg != null) { + try { + reg.close(); + } catch (Exception e) { + logger.warn("Failed to stop {} Statistics tracker for node {}", statName(), getNodeIdentifier(), e); + } + reg = null; + } + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java new file mode 100644 index 0000000000..c29b6a7730 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java @@ -0,0 +1,115 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.Future; + +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.JdkFutureAdapters; + +abstract class AbstractStatsTracker { + private static final Logger logger = LoggerFactory.getLogger(AbstractStatsTracker.class); + private final FutureCallback> callback = + new FutureCallback>() { + @Override + public void onSuccess(RpcResult result) { + if (result.isSuccessful()) { + final TransactionId id = result.getResult().getTransactionId(); + if (id == null) { + final Throwable t = new UnsupportedOperationException("No protocol support"); + t.fillInStackTrace(); + onFailure(t); + } else { + context.registerTransaction(id); + } + } else { + logger.debug("Statistics request failed: {}", result.getErrors()); + + final Throwable t = new RPCFailedException("Failed to send statistics request", result.getErrors()); + t.fillInStackTrace(); + onFailure(t); + } + } + + @Override + public void onFailure(Throwable t) { + logger.debug("Failed to send statistics request", t); + } + }; + + private final Map trackedItems = new HashMap<>(); + private final FlowCapableContext context; + private final long lifetimeNanos; + + protected AbstractStatsTracker(final FlowCapableContext context, final long lifetimeNanos) { + this.context = Preconditions.checkNotNull(context); + this.lifetimeNanos = lifetimeNanos; + } + + protected final InstanceIdentifierBuilder getNodeIdentifierBuilder() { + return InstanceIdentifier.builder(getNodeIdentifier()); + } + + protected final NodeRef getNodeRef() { + return context.getNodeRef(); + } + + protected final InstanceIdentifier getNodeIdentifier() { + return context.getNodeIdentifier(); + } + + protected final void requestHelper(Future> future) { + Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), callback); + } + + protected final DataModificationTransaction startTransaction() { + return context.startDataModification(); + } + + protected abstract void cleanupSingleStat(DataModificationTransaction trans, K item); + protected abstract K updateSingleStat(DataModificationTransaction trans, I item); + + public final synchronized void updateStats(List list) { + final Long expiryTime = System.nanoTime() + lifetimeNanos; + final DataModificationTransaction trans = startTransaction(); + + for (final I item : list) { + trackedItems.put(updateSingleStat(trans, item), expiryTime); + } + + trans.commit(); + } + + public final synchronized void cleanup(final DataModificationTransaction trans, long now) { + for (Iterator> it = trackedItems.entrySet().iterator();it.hasNext();){ + Entry e = it.next(); + if (now > e.getValue()) { + cleanupSingleStat(trans, e.getKey()); + it.remove(); + } + } + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java new file mode 100644 index 0000000000..520b344199 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java @@ -0,0 +1,27 @@ +/* + * 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.md.statistics.manager; + +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Interface exposed to AbstractStatsTracker by its parent NodeStatisticsHandler. + * While we could simply exist without this interface, its purpose is to document + * the contract between the two classes. + */ +interface FlowCapableContext { + InstanceIdentifier getNodeIdentifier(); + NodeRef getNodeRef(); + DataModificationTransaction startDataModification(); + void registerTransaction(TransactionId id); + void registerTableTransaction(TransactionId id, Short tableId); +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java new file mode 100644 index 0000000000..bb1544c57a --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java @@ -0,0 +1,111 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import java.util.Collection; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +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.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; +import com.google.common.collect.Sets; + +/** + * There is a single instance of this class and that instance is responsible for + * monitoring the operational data store for nodes being created/deleted and + * notifying StatisticsProvider. These events then control the lifecycle of + * NodeStatisticsHandler for a particular switch. + */ +final class FlowCapableTracker implements DataChangeListener { + private static final Logger logger = LoggerFactory.getLogger(FlowCapableTracker.class); + + private final InstanceIdentifier root; + private final StatisticsProvider stats; + + private final Predicate> filterIdentifiers = new Predicate>() { + @Override + public boolean apply(final InstanceIdentifier input) { + /* + * This notification has been triggered either by the ancestor, + * descendant or directly for the FlowCapableNode itself. We + * are not interested descendants, so let's prune them based + * on the depth of their identifier. + */ + if (root.getPath().size() < input.getPath().size()) { + logger.debug("Ignoring notification for descendant {}", input); + return false; + } + + logger.debug("Including notification for {}", input); + return true; + } + }; + + public FlowCapableTracker(final StatisticsProvider stats, InstanceIdentifier root) { + this.stats = Preconditions.checkNotNull(stats); + this.root = Preconditions.checkNotNull(root); + } + + /* + * This method is synchronized because we want to make sure to serialize input + * from the datastore. Competing add/remove could be problematic otherwise. + */ + @Override + public synchronized void onDataChanged(final DataChangeEvent, DataObject> change) { + logger.debug("Tracker at root {} processing notification", root); + + /* + * First process all the identifiers which were removed, trying to figure out + * whether they constitute removal of FlowCapableNode. + */ + final Collection removedNodes = + Collections2.filter(Collections2.transform( + Sets.filter(change.getRemovedOperationalData(), filterIdentifiers), + new Function, NodeKey>() { + @Override + public NodeKey apply(final InstanceIdentifier input) { + final NodeKey key = input.firstKeyOf(Node.class, NodeKey.class); + if (key == null) { + // FIXME: do we have a backup plan? + logger.info("Failed to extract node key from {}", input); + } + return key; + } + }), Predicates.notNull()); + stats.stopNodeHandlers(removedNodes); + + final Collection addedNodes = + Collections2.filter(Collections2.transform( + Sets.filter(change.getCreatedOperationalData().keySet(), filterIdentifiers), + new Function, NodeKey>() { + @Override + public NodeKey apply(final InstanceIdentifier input) { + final NodeKey key = input.firstKeyOf(Node.class, NodeKey.class); + if (key == null) { + // FIXME: do we have a backup plan? + logger.info("Failed to extract node key from {}", input); + } + return key; + } + }), Predicates.notNull()); + stats.startNodeHandlers(addedNodes); + + logger.debug("Tracker at root {} finished processing notification", root); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java new file mode 100644 index 0000000000..b5b39d94d2 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java @@ -0,0 +1,59 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; + +final class FlowStatsEntry { + private final Short tableId; + private final Flow flow; + + public FlowStatsEntry(Short tableId, Flow flow){ + this.tableId = tableId; + this.flow = flow; + } + + public Short getTableId() { + return tableId; + } + + public Flow getFlow() { + return flow; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((flow == null) ? 0 : flow.hashCode()); + result = prime * result + ((tableId == null) ? 0 : tableId.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + FlowStatsEntry other = (FlowStatsEntry) obj; + if (flow == null) { + if (other.flow != null) + return false; + } else if (!flow.equals(other.flow)) + return false; + if (tableId == null) { + if (other.tableId != null) + return false; + } else if (!tableId.equals(other.tableId)) + return false; + return true; + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java new file mode 100644 index 0000000000..90ddc28acd --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java @@ -0,0 +1,272 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import java.util.Map.Entry; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +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.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.statistics.rev130819.FlowStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class FlowStatsTracker extends AbstractListeningStatsTracker { + private static final Logger logger = LoggerFactory.getLogger(FlowStatsTracker.class); + private final OpendaylightFlowStatisticsService flowStatsService; + private int unaccountedFlowsCounter = 1; + + FlowStatsTracker(OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context, long lifetimeNanos) { + super(context, lifetimeNanos); + this.flowStatsService = flowStatsService; + } + + @Override + protected void cleanupSingleStat(DataModificationTransaction trans, FlowStatsEntry item) { + InstanceIdentifier flowRef = getNodeIdentifierBuilder() + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(item.getTableId())) + .child(Flow.class,item.getFlow().getKey()) + .augmentation(FlowStatisticsData.class).toInstance(); + trans.removeOperationalData(flowRef); + } + + @Override + protected FlowStatsEntry updateSingleStat(DataModificationTransaction trans, FlowAndStatisticsMapList map) { + short tableId = map.getTableId(); + + FlowBuilder flowBuilder = new FlowBuilder(); + + FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder(); + + FlowBuilder flow = new FlowBuilder(); + flow.setContainerName(map.getContainerName()); + flow.setBufferId(map.getBufferId()); + flow.setCookie(map.getCookie()); + flow.setCookieMask(map.getCookieMask()); + flow.setFlags(map.getFlags()); + flow.setFlowName(map.getFlowName()); + flow.setHardTimeout(map.getHardTimeout()); + if(map.getFlowId() != null) + flow.setId(new FlowId(map.getFlowId().getValue())); + flow.setIdleTimeout(map.getIdleTimeout()); + flow.setInstallHw(map.isInstallHw()); + flow.setInstructions(map.getInstructions()); + if(map.getFlowId()!= null) + flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue()))); + flow.setMatch(map.getMatch()); + flow.setOutGroup(map.getOutGroup()); + flow.setOutPort(map.getOutPort()); + flow.setPriority(map.getPriority()); + flow.setStrict(map.isStrict()); + flow.setTableId(tableId); + + Flow flowRule = flow.build(); + + FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder(); + stats.setByteCount(map.getByteCount()); + stats.setPacketCount(map.getPacketCount()); + stats.setDuration(map.getDuration()); + + GenericStatistics flowStats = stats.build(); + + //Augment the data to the flow node + + FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder(); + flowStatistics.setByteCount(flowStats.getByteCount()); + flowStatistics.setPacketCount(flowStats.getPacketCount()); + flowStatistics.setDuration(flowStats.getDuration()); + flowStatistics.setContainerName(map.getContainerName()); + flowStatistics.setBufferId(map.getBufferId()); + flowStatistics.setCookie(map.getCookie()); + flowStatistics.setCookieMask(map.getCookieMask()); + flowStatistics.setFlags(map.getFlags()); + flowStatistics.setFlowName(map.getFlowName()); + flowStatistics.setHardTimeout(map.getHardTimeout()); + flowStatistics.setIdleTimeout(map.getIdleTimeout()); + flowStatistics.setInstallHw(map.isInstallHw()); + flowStatistics.setInstructions(map.getInstructions()); + flowStatistics.setMatch(map.getMatch()); + flowStatistics.setOutGroup(map.getOutGroup()); + flowStatistics.setOutPort(map.getOutPort()); + flowStatistics.setPriority(map.getPriority()); + flowStatistics.setStrict(map.isStrict()); + flowStatistics.setTableId(tableId); + + flowStatisticsData.setFlowStatistics(flowStatistics.build()); + + logger.debug("Flow : {}",flowRule.toString()); + logger.debug("Statistics to augment : {}",flowStatistics.build().toString()); + + InstanceIdentifier tableRef = getNodeIdentifierBuilder() + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); + + //TODO: Not a good way to do it, need to figure out better way. + //TODO: major issue in any alternate approach is that flow key is incrementally assigned + //to the flows stored in data store. + // Augment same statistics to all the matching masked flow + Table table= (Table)trans.readConfigurationData(tableRef); + if(table != null){ + for(Flow existingFlow : table.getFlow()){ + logger.debug("Existing flow in data store : {}",existingFlow.toString()); + if(FlowComparator.flowEquals(flowRule,existingFlow)){ + InstanceIdentifier flowRef = getNodeIdentifierBuilder() + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class,existingFlow.getKey()).toInstance(); + flowBuilder.setKey(existingFlow.getKey()); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); + logger.debug("Found matching flow in the datastore, augmenting statistics"); + // Update entry with timestamp of latest response + flow.setKey(existingFlow.getKey()); + FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build()); + trans.putOperationalData(flowRef, flowBuilder.build()); + return flowStatsEntry; + } + } + } + + table = (Table)trans.readOperationalData(tableRef); + if(table != null){ + for(Flow existingFlow : table.getFlow()){ + FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class); + if(augmentedflowStatisticsData != null){ + FlowBuilder existingOperationalFlow = new FlowBuilder(); + existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics()); + logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString()); + if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){ + InstanceIdentifier flowRef = getNodeIdentifierBuilder() + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class,existingFlow.getKey()).toInstance(); + flowBuilder.setKey(existingFlow.getKey()); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); + logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics"); + // Update entry with timestamp of latest response + flow.setKey(existingFlow.getKey()); + FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build()); + trans.putOperationalData(flowRef, flowBuilder.build()); + return flowStatsEntry; + } + } + } + } + + String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter); + this.unaccountedFlowsCounter++; + FlowKey newFlowKey = new FlowKey(new FlowId(flowKey)); + InstanceIdentifier flowRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class,newFlowKey).toInstance(); + flowBuilder.setKey(newFlowKey); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); + logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow", + flowBuilder.build()); + + // Update entry with timestamp of latest response + flow.setKey(newFlowKey); + FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build()); + trans.putOperationalData(flowRef, flowBuilder.build()); + return flowStatsEntry; + } + + @Override + protected InstanceIdentifier listenPath() { + return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Table.class).child(Flow.class).build(); + } + + @Override + protected String statName() { + return "Flow"; + } + + public void requestAllFlowsAllTables() { + if (flowStatsService != null) { + final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input = new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder(); + input.setNode(getNodeRef()); + + requestHelper(flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build())); + } + } + + public void requestAggregateFlows(final TableKey key) { + if (flowStatsService != null) { + GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = + new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder(); + + input.setNode(getNodeRef()); + input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(key.getId())); + requestHelper(flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build())); + } + } + + public void requestFlow(final Flow flow) { + if (flowStatsService != null) { + final GetFlowStatisticsFromFlowTableInputBuilder input = + new GetFlowStatisticsFromFlowTableInputBuilder(flow); + input.setNode(getNodeRef()); + + requestHelper(flowStatsService.getFlowStatisticsFromFlowTable(input.build())); + } + } + + @Override + public void onDataChanged(DataChangeEvent, DataObject> change) { + for (Entry, DataObject> e : change.getCreatedConfigurationData().entrySet()) { + if (Flow.class.equals(e.getKey().getTargetType())) { + final Flow flow = (Flow) e.getValue(); + logger.debug("Key {} triggered request for flow {}", e.getKey(), flow); + requestFlow(flow); + } else { + logger.debug("Ignoring key {}", e.getKey()); + } + } + + final DataModificationTransaction trans = startTransaction(); + for (InstanceIdentifier key : change.getRemovedConfigurationData()) { + if (Flow.class.equals(key.getTargetType())) { + @SuppressWarnings("unchecked") + final InstanceIdentifier flow = (InstanceIdentifier)key; + final InstanceIdentifier del = InstanceIdentifier.builder(flow) + .augmentation(FlowStatisticsData.class).build(); + logger.debug("Key {} triggered remove of augmentation {}", key, del); + + trans.removeOperationalData(del); + } + } + trans.commit(); + } + + @Override + public void start(final DataBrokerService dbs) { + if (flowStatsService == null) { + logger.debug("No Flow Statistics service, not subscribing to flows on node {}", getNodeIdentifier()); + return; + } + + super.start(dbs); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java new file mode 100644 index 0000000000..3fe68c111a --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java @@ -0,0 +1,72 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +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.table.statistics.rev131215.FlowTableStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +final class FlowTableStatsTracker extends AbstractStatsTracker { + private final Set privateTables = new ConcurrentSkipListSet<>(); + private final Set tables = Collections.unmodifiableSet(privateTables); + private final OpendaylightFlowTableStatisticsService flowTableStatsService; + + FlowTableStatsTracker(OpendaylightFlowTableStatisticsService flowTableStatsService, final FlowCapableContext context, long lifetimeNanos) { + super(context, lifetimeNanos); + this.flowTableStatsService = flowTableStatsService; + } + + Set getTables() { + return tables; + } + + @Override + protected void cleanupSingleStat(DataModificationTransaction trans, FlowTableAndStatisticsMap item) { + // TODO: do we want to do this? + } + + @Override + protected FlowTableAndStatisticsMap updateSingleStat(DataModificationTransaction trans, FlowTableAndStatisticsMap item) { + + InstanceIdentifier
tableRef = getNodeIdentifierBuilder() + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(item.getTableId().getValue())).build(); + + FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder(); + final FlowTableStatistics stats = new FlowTableStatisticsBuilder(item).build(); + statisticsDataBuilder.setFlowTableStatistics(stats); + + TableBuilder tableBuilder = new TableBuilder(); + tableBuilder.setKey(new TableKey(item.getTableId().getValue())); + tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build()); + trans.putOperationalData(tableRef, tableBuilder.build()); + return item; + } + + public void request() { + if (flowTableStatsService != null) { + final GetFlowTablesStatisticsInputBuilder input = new GetFlowTablesStatisticsInputBuilder(); + input.setNode(getNodeRef()); + + requestHelper(flowTableStatsService.getFlowTablesStatistics(input.build())); + } + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java new file mode 100644 index 0000000000..8aebd6b249 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java @@ -0,0 +1,116 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class GroupDescStatsTracker extends AbstractListeningStatsTracker { + private static final Logger logger = LoggerFactory.getLogger(GroupDescStatsTracker.class); + private final OpendaylightGroupStatisticsService groupStatsService; + + public GroupDescStatsTracker(OpendaylightGroupStatisticsService groupStatsService, final FlowCapableContext context, final long lifetimeNanos) { + super(context, lifetimeNanos); + this.groupStatsService = groupStatsService; + } + + @Override + protected GroupDescStats updateSingleStat(DataModificationTransaction trans, GroupDescStats item) { + GroupBuilder groupBuilder = new GroupBuilder(); + GroupKey groupKey = new GroupKey(item.getGroupId()); + groupBuilder.setKey(groupKey); + + InstanceIdentifier groupRef = getNodeIdentifierBuilder() + .augmentation(FlowCapableNode.class).child(Group.class,groupKey).build(); + + NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder(); + groupDesc.setGroupDesc(new GroupDescBuilder(item).build()); + + //Update augmented data + groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build()); + + trans.putOperationalData(groupRef, groupBuilder.build()); + return item; + } + + @Override + protected void cleanupSingleStat(DataModificationTransaction trans, GroupDescStats item) { + InstanceIdentifier groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class) + .child(Group.class, new GroupKey(item.getGroupId())).augmentation(NodeGroupDescStats.class).build(); + trans.removeOperationalData(groupRef); + } + + @Override + protected InstanceIdentifier listenPath() { + return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Group.class).build(); + } + + @Override + protected String statName() { + return "Group Descriptor"; + } + + public void request() { + if (groupStatsService != null) { + final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder(); + input.setNode(getNodeRef()); + + requestHelper(groupStatsService.getGroupDescription(input.build())); + } + } + + @Override + public void onDataChanged(DataChangeEvent, DataObject> change) { + for (InstanceIdentifier key : change.getCreatedConfigurationData().keySet()) { + if (Group.class.equals(key.getTargetType())) { + logger.debug("Key {} triggered request", key); + request(); + } else { + logger.debug("Ignoring key {}", key); + } + } + + final DataModificationTransaction trans = startTransaction(); + for (InstanceIdentifier key : change.getRemovedConfigurationData()) { + if (Group.class.equals(key.getTargetType())) { + @SuppressWarnings("unchecked") + InstanceIdentifier group = (InstanceIdentifier)key; + InstanceIdentifier del = InstanceIdentifier.builder(group).augmentation(NodeGroupDescStats.class).toInstance(); + logger.debug("Key {} triggered remove of augmentation {}", key, del); + + trans.removeOperationalData(del); + } + } + trans.commit(); + } + + @Override + public void start(final DataBrokerService dbs) { + if (groupStatsService == null) { + logger.debug("No Group Statistics service, not subscribing to groups on node {}", getNodeIdentifier()); + return; + } + + super.start(dbs); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java new file mode 100644 index 0000000000..1af8e4e9f1 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java @@ -0,0 +1,107 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +final class GroupStatsTracker extends AbstractListeningStatsTracker { + private static final Logger logger = LoggerFactory.getLogger(GroupStatsTracker.class); + private final OpendaylightGroupStatisticsService groupStatsService; + + GroupStatsTracker(OpendaylightGroupStatisticsService groupStatsService, FlowCapableContext context, long lifetimeNanos) { + super(context, lifetimeNanos); + this.groupStatsService = Preconditions.checkNotNull(groupStatsService); + } + + @Override + protected void cleanupSingleStat(DataModificationTransaction trans, GroupStats item) { + InstanceIdentifier groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class) + .child(Group.class, new GroupKey(item.getGroupId())).augmentation(NodeGroupStatistics.class).build(); + trans.removeOperationalData(groupRef); + } + + @Override + protected GroupStats updateSingleStat(DataModificationTransaction trans, + GroupStats item) { + GroupBuilder groupBuilder = new GroupBuilder(); + GroupKey groupKey = new GroupKey(item.getGroupId()); + groupBuilder.setKey(groupKey); + + InstanceIdentifier groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class) + .child(Group.class,groupKey).build(); + + NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder(); + groupStatisticsBuilder.setGroupStatistics(new GroupStatisticsBuilder(item).build()); + + //Update augmented data + groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build()); + trans.putOperationalData(groupRef, groupBuilder.build()); + return item; + } + + @Override + protected InstanceIdentifier listenPath() { + return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Group.class).build(); + } + + @Override + protected String statName() { + return "Group"; + } + + public void request() { + final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder(); + input.setNode(getNodeRef()); + + requestHelper(groupStatsService.getAllGroupStatistics(input.build())); + } + + @Override + public void onDataChanged(DataChangeEvent, DataObject> change) { + final DataModificationTransaction trans = startTransaction(); + for (InstanceIdentifier key : change.getRemovedConfigurationData()) { + if (Group.class.equals(key.getTargetType())) { + @SuppressWarnings("unchecked") + InstanceIdentifier group = (InstanceIdentifier)key; + InstanceIdentifier del = InstanceIdentifier.builder(group).augmentation(NodeGroupStatistics.class).toInstance(); + logger.debug("Key {} triggered remove of augmentation {}", key, del); + + trans.removeOperationalData(del); + } + } + trans.commit(); + } + + @Override + public void start(final DataBrokerService dbs) { + if (groupStatsService == null) { + logger.debug("No Group Statistics service, not subscribing to groups on node {}", getNodeIdentifier()); + return; + } + + super.start(dbs); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java new file mode 100644 index 0000000000..4b95925705 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java @@ -0,0 +1,111 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class MeterConfigStatsTracker extends AbstractListeningStatsTracker { + private static final Logger logger = LoggerFactory.getLogger(MeterConfigStatsTracker.class); + private final OpendaylightMeterStatisticsService meterStatsService; + + protected MeterConfigStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context, long lifetimeNanos) { + super(context, lifetimeNanos); + this.meterStatsService = meterStatsService; + } + + @Override + protected void cleanupSingleStat(DataModificationTransaction trans, MeterConfigStats item) { + InstanceIdentifier meterRef = getNodeIdentifierBuilder() + .augmentation(FlowCapableNode.class) + .child(Meter.class, new MeterKey(item.getMeterId())) + .augmentation(NodeMeterConfigStats.class).build(); + trans.removeOperationalData(meterRef); + } + + @Override + protected MeterConfigStats updateSingleStat(DataModificationTransaction trans, MeterConfigStats item) { + MeterBuilder meterBuilder = new MeterBuilder(); + MeterKey meterKey = new MeterKey(item.getMeterId()); + meterBuilder.setKey(meterKey); + + InstanceIdentifier meterRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class) + .child(Meter.class,meterKey).toInstance(); + + NodeMeterConfigStatsBuilder meterConfig = new NodeMeterConfigStatsBuilder(); + meterConfig.setMeterConfigStats(new MeterConfigStatsBuilder(item).build()); + + //Update augmented data + meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build()); + + trans.putOperationalData(meterRef, meterBuilder.build()); + return item; + } + + public void request() { + if (meterStatsService != null) { + GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder(); + input.setNode(getNodeRef()); + + requestHelper(meterStatsService.getAllMeterConfigStatistics(input.build())); + } + } + + @Override + public void onDataChanged(DataChangeEvent, DataObject> change) { + final DataModificationTransaction trans = startTransaction(); + + for (InstanceIdentifier key : change.getRemovedConfigurationData()) { + if (Meter.class.equals(key.getTargetType())) { + @SuppressWarnings("unchecked") + InstanceIdentifier meter = (InstanceIdentifier)key; + + InstanceIdentifier nodeMeterStatisticsAugmentation = + InstanceIdentifier.builder(meter).augmentation(NodeMeterConfigStats.class).toInstance(); + trans.removeOperationalData(nodeMeterStatisticsAugmentation); + } + } + + trans.commit(); + } + + @Override + protected InstanceIdentifier listenPath() { + return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Meter.class).build(); + } + + @Override + protected String statName() { + return "Meter Config"; + } + + @Override + public void start(final DataBrokerService dbs) { + if (meterStatsService == null) { + logger.debug("No Meter Statistics service, not subscribing to meter on node {}", getNodeIdentifier()); + return; + } + + super.start(dbs); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java new file mode 100644 index 0000000000..091cbcc1a0 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java @@ -0,0 +1,114 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class MeterStatsTracker extends AbstractListeningStatsTracker { + private static final Logger logger = LoggerFactory.getLogger(MeterStatsTracker.class); + private final OpendaylightMeterStatisticsService meterStatsService; + + MeterStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context, long lifetimeNanos) { + super(context, lifetimeNanos); + this.meterStatsService = meterStatsService; + } + + @Override + protected void cleanupSingleStat(DataModificationTransaction trans, MeterStats item) { + InstanceIdentifier meterRef = getNodeIdentifierBuilder() + .augmentation(FlowCapableNode.class) + .child(Meter.class,new MeterKey(item.getMeterId())) + .augmentation(NodeMeterStatistics.class).build(); + trans.removeOperationalData(meterRef); + } + + @Override + protected MeterStats updateSingleStat(DataModificationTransaction trans, MeterStats item) { + MeterBuilder meterBuilder = new MeterBuilder(); + MeterKey meterKey = new MeterKey(item.getMeterId()); + meterBuilder.setKey(meterKey); + + InstanceIdentifier meterRef = getNodeIdentifierBuilder() + .augmentation(FlowCapableNode.class).child(Meter.class,meterKey).build(); + + NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder(); + meterStatsBuilder.setMeterStatistics(new MeterStatisticsBuilder(item).build()); + + //Update augmented data + meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build()); + trans.putOperationalData(meterRef, meterBuilder.build()); + return item; + } + + public void request() { + if (meterStatsService != null) { + GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder(); + input.setNode(getNodeRef()); + + requestHelper(meterStatsService.getAllMeterStatistics(input.build())); + } + } + + @Override + public void onDataChanged(DataChangeEvent, DataObject> change) { + for (InstanceIdentifier key : change.getCreatedConfigurationData().keySet()) { + if (Meter.class.equals(key.getTargetType())) { + request(); + } + } + + final DataModificationTransaction trans = startTransaction(); + for (InstanceIdentifier key : change.getRemovedConfigurationData()) { + if (Meter.class.equals(key.getTargetType())) { + @SuppressWarnings("unchecked") + InstanceIdentifier meter = (InstanceIdentifier)key; + + InstanceIdentifier nodeMeterStatisticsAugmentation = + InstanceIdentifier.builder(meter).augmentation(NodeMeterStatistics.class).toInstance(); + trans.removeOperationalData(nodeMeterStatisticsAugmentation); + } + } + trans.commit(); + } + + @Override + protected InstanceIdentifier listenPath() { + return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Meter.class).build(); + } + + @Override + protected String statName() { + return "Meter"; + } + + @Override + public void start(final DataBrokerService dbs) { + if (meterStatsService == null) { + logger.debug("No Meter Statistics service, not subscribing to meters on node {}", getNodeIdentifier()); + return; + } + + super.start(dbs); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java index 6f58708e1b..56b205216f 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java @@ -7,63 +7,53 @@ */ package org.opendaylight.controller.md.statistics.manager; -import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; + +import com.google.common.base.Preconditions; /** - * Main responsibility of the class is to manage multipart response + * Main responsibility of the class is to manage multipart response * for multipart request. It also handles the flow aggregate request - * and response mapping. + * and response mapping. * @author avishnoi@in.ibm.com * */ -public class MultipartMessageManager { - +class MultipartMessageManager { /* - * Map for tx id and type of request, to keep track of all the request sent - * by Statistics Manager. Statistics Manager won't entertain any multipart - * response for which it didn't send the request. + * Map for tx id and type of request, to keep track of all the request sent + * by Statistics Manager. Statistics Manager won't entertain any multipart + * response for which it didn't send the request. */ - - private static Map txIdToRequestTypeMap = new ConcurrentHashMap(); + private final Map txIdToRequestTypeMap = new ConcurrentHashMap<>(); /* * Map to keep track of the request tx id for flow table statistics request. * Because flow table statistics multi part response do not contains the table id. */ - private static Map txIdTotableIdMap = new ConcurrentHashMap(); - - private final int NUMBER_OF_WAIT_CYCLES =2; + private final Map txIdTotableIdMap = new ConcurrentHashMap<>(); + private final long lifetimeNanos; + + public MultipartMessageManager(long lifetimeNanos) { + this.lifetimeNanos = lifetimeNanos; + } - class TxIdEntry{ + private static final class TxIdEntry { private final TransactionId txId; - private final NodeId nodeId; - private final StatsRequestType requestType; - - public TxIdEntry(NodeId nodeId, TransactionId txId, StatsRequestType requestType){ + + public TxIdEntry(TransactionId txId) { this.txId = txId; - this.nodeId = nodeId; - this.requestType = requestType; } public TransactionId getTxId() { return txId; } - public NodeId getNodeId() { - return nodeId; - } - public StatsRequestType getRequestType() { - return requestType; - } @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + getOuterType().hashCode(); - result = prime * result + ((nodeId == null) ? 0 : nodeId.hashCode()); result = prime * result + ((txId == null) ? 0 : txId.hashCode()); return result; } @@ -79,16 +69,7 @@ public class MultipartMessageManager { return false; } TxIdEntry other = (TxIdEntry) obj; - if (!getOuterType().equals(other.getOuterType())) { - return false; - } - if (nodeId == null) { - if (other.nodeId != null) { - return false; - } - } else if (!nodeId.equals(other.nodeId)) { - return false; - } + if (txId == null) { if (other.txId != null) { return false; @@ -98,75 +79,60 @@ public class MultipartMessageManager { } return true; } - private MultipartMessageManager getOuterType() { - return MultipartMessageManager.this; - } + @Override public String toString() { - return "TxIdEntry [txId=" + txId + ", nodeId=" + nodeId + ", requestType=" + requestType + "]"; + return "TxIdEntry [txId=" + txId + ']'; } } - public MultipartMessageManager(){} - - public Short getTableIdForTxId(NodeId nodeId,TransactionId id){ - - return txIdTotableIdMap.get(new TxIdEntry(nodeId,id,null)); - - } - - public void setTxIdAndTableIdMapEntry(NodeId nodeId, TransactionId id,Short tableId){ - if(id == null) - return; - txIdTotableIdMap.put(new TxIdEntry(nodeId,id,null), tableId); + public void recordExpectedTableTransaction(TransactionId id, Short tableId) { + recordExpectedTransaction(id); + txIdTotableIdMap.put(new TxIdEntry(id), Preconditions.checkNotNull(tableId)); } - - public boolean isRequestTxIdExist(NodeId nodeId, TransactionId id, Boolean moreRepliesToFollow){ - TxIdEntry entry = new TxIdEntry(nodeId,id,null); - if(moreRepliesToFollow.booleanValue()){ - return txIdToRequestTypeMap.containsKey(entry); - }else{ - return txIdToRequestTypeMap.remove(entry)==null?false:true; + + public Short isExpectedTableTransaction(TransactionAware transaction, Boolean more) { + if (!isExpectedTransaction(transaction, more)) { + return null; + } + + final TxIdEntry key = new TxIdEntry(transaction.getTransactionId()); + if (more != null && more.booleanValue()) { + return txIdTotableIdMap.get(key); + } else { + return txIdTotableIdMap.remove(key); } } - public void addTxIdToRequestTypeEntry (NodeId nodeId, TransactionId id,StatsRequestType type){ - if(id == null) - return; - TxIdEntry entry = new TxIdEntry(nodeId,id,type); + + public void recordExpectedTransaction(TransactionId id) { + TxIdEntry entry = new TxIdEntry(Preconditions.checkNotNull(id)); txIdToRequestTypeMap.put(entry, getExpiryTime()); } - public boolean removeTxId(NodeId nodeId, TransactionId id){ - TxIdEntry entry = new TxIdEntry(nodeId,id,null); - return txIdToRequestTypeMap.remove(entry)==null?false:true; - } - - private Date getExpiryTime(){ - Date expires = new Date(); - expires.setTime(expires.getTime()+StatisticsProvider.STATS_THREAD_EXECUTION_TIME*NUMBER_OF_WAIT_CYCLES); - return expires; + + public boolean isExpectedTransaction(TransactionAware transaction, Boolean more) { + TxIdEntry entry = new TxIdEntry(transaction.getTransactionId()); + if (more != null && more.booleanValue()) { + return txIdToRequestTypeMap.containsKey(entry); + } else { + return txIdToRequestTypeMap.remove(entry) != null; + } } - public enum StatsRequestType{ - ALL_FLOW, - AGGR_FLOW, - ALL_PORT, - ALL_FLOW_TABLE, - ALL_QUEUE_STATS, - ALL_GROUP, - ALL_METER, - GROUP_DESC, - METER_CONFIG + private Long getExpiryTime() { + return System.nanoTime() + lifetimeNanos; } - - public void cleanStaleTransactionIds(){ + + public void cleanStaleTransactionIds() { + final long now = System.nanoTime(); + for (Iterator it = txIdToRequestTypeMap.keySet().iterator();it.hasNext();){ TxIdEntry txIdEntry = it.next(); - Date now = new Date(); - Date expiryTime = txIdToRequestTypeMap.get(txIdEntry); - if(now.after(expiryTime)){ + + Long expiryTime = txIdToRequestTypeMap.get(txIdEntry); + if(now > expiryTime){ it.remove(); txIdTotableIdMap.remove(txIdEntry); - } + } } } } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java new file mode 100644 index 0000000000..00bd27402f --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java @@ -0,0 +1,84 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class NodeConnectorStatsTracker extends AbstractStatsTracker { + private static final Logger logger = LoggerFactory.getLogger(NodeConnectorStatsTracker.class); + private final OpendaylightPortStatisticsService portStatsService; + + NodeConnectorStatsTracker(final OpendaylightPortStatisticsService portStatsService, final FlowCapableContext context, long lifetimeNanos) { + super(context, lifetimeNanos); + this.portStatsService = portStatsService; + } + + @Override + protected void cleanupSingleStat(DataModificationTransaction trans, NodeConnectorStatisticsAndPortNumberMap item) { + // TODO Auto-generated method stub + } + + @Override + protected NodeConnectorStatisticsAndPortNumberMap updateSingleStat(DataModificationTransaction trans, NodeConnectorStatisticsAndPortNumberMap item) { + FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder + = new FlowCapableNodeConnectorStatisticsBuilder(); + statisticsBuilder.setBytes(item.getBytes()); + statisticsBuilder.setCollisionCount(item.getCollisionCount()); + statisticsBuilder.setDuration(item.getDuration()); + statisticsBuilder.setPackets(item.getPackets()); + statisticsBuilder.setReceiveCrcError(item.getReceiveCrcError()); + statisticsBuilder.setReceiveDrops(item.getReceiveDrops()); + statisticsBuilder.setReceiveErrors(item.getReceiveErrors()); + statisticsBuilder.setReceiveFrameError(item.getReceiveFrameError()); + statisticsBuilder.setReceiveOverRunError(item.getReceiveOverRunError()); + statisticsBuilder.setTransmitDrops(item.getTransmitDrops()); + statisticsBuilder.setTransmitErrors(item.getTransmitErrors()); + + //Augment data to the node-connector + FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder = + new FlowCapableNodeConnectorStatisticsDataBuilder(); + + statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build()); + + InstanceIdentifier nodeConnectorRef = getNodeIdentifierBuilder() + .child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId())).build(); + + // FIXME: can we bypass this read? + NodeConnector nodeConnector = (NodeConnector)trans.readOperationalData(nodeConnectorRef); + if(nodeConnector != null){ + final FlowCapableNodeConnectorStatisticsData stats = statisticsDataBuilder.build(); + logger.debug("Augmenting port statistics {} to port {}",stats,nodeConnectorRef.toString()); + NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder(); + nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats); + trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build()); + } + + return item; + } + + public void request() { + if (portStatsService != null) { + final GetAllNodeConnectorsStatisticsInputBuilder input = new GetAllNodeConnectorsStatisticsInputBuilder(); + input.setNode(getNodeRef()); + + requestHelper(portStatsService.getAllNodeConnectorsStatistics(input.build())); + } + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java index 6d0b5ea0e3..6796b4eb87 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java @@ -7,90 +7,52 @@ */ package org.opendaylight.controller.md.statistics.manager; -import java.util.HashMap; -import java.util.Iterator; +import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.TimeUnit; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey; 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.statistics.rev130819.AggregateFlowStatisticsData; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService; import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService; import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -103,370 +65,124 @@ import com.google.common.base.Preconditions; * * @author avishnoi@in.ibm.com */ -public class NodeStatisticsHandler { +public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableContext { private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsHandler.class); + + private static final long STATS_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(15); + private static final long FIRST_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(5); private static final int NUMBER_OF_WAIT_CYCLES = 2; - private final Map groupDescStatsUpdate = new HashMap<>(); - private final Map meterConfigStatsUpdate = new HashMap<>(); - private final Map flowStatsUpdate = new HashMap<>(); - private final Map queuesStatsUpdate = new HashMap<>(); + private final MultipartMessageManager msgManager; private final InstanceIdentifier targetNodeIdentifier; - private final StatisticsProvider statisticsProvider; + private final FlowStatsTracker flowStats; + private final FlowTableStatsTracker flowTableStats; + private final GroupDescStatsTracker groupDescStats; + private final GroupStatsTracker groupStats; + private final MeterConfigStatsTracker meterConfigStats; + private final MeterStatsTracker meterStats; + private final NodeConnectorStatsTracker nodeConnectorStats; + private final QueueStatsTracker queueStats; + private final DataProviderService dps; + private final NodeRef targetNodeRef; private final NodeKey targetNodeKey; - private int unaccountedFlowsCounter = 1; - - public NodeStatisticsHandler(StatisticsProvider statisticsProvider, NodeKey nodeKey){ - this.statisticsProvider = Preconditions.checkNotNull(statisticsProvider); - this.targetNodeKey = Preconditions.checkNotNull(nodeKey); - this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build(); - } - - public class FlowEntry { - private final Short tableId; - private final Flow flow; - - public FlowEntry(Short tableId, Flow flow){ - this.tableId = tableId; - this.flow = flow; - } - - public Short getTableId() { - return tableId; - } - - public Flow getFlow() { - return flow; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + getOuterType().hashCode(); - result = prime * result + ((flow == null) ? 0 : flow.hashCode()); - result = prime * result + ((tableId == null) ? 0 : tableId.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - FlowEntry other = (FlowEntry) obj; - if (!getOuterType().equals(other.getOuterType())) - return false; - if (flow == null) { - if (other.flow != null) - return false; - } else if (!flow.equals(other.flow)) - return false; - if (tableId == null) { - if (other.tableId != null) - return false; - } else if (!tableId.equals(other.tableId)) - return false; - return true; - } - - private NodeStatisticsHandler getOuterType() { - return NodeStatisticsHandler.this; - } - } - - private static final class QueueEntry{ - private final NodeConnectorId nodeConnectorId; - private final QueueId queueId; - public QueueEntry(NodeConnectorId ncId, QueueId queueId){ - this.nodeConnectorId = ncId; - this.queueId = queueId; - } - public NodeConnectorId getNodeConnectorId() { - return nodeConnectorId; - } - public QueueId getQueueId() { - return queueId; - } + private final TimerTask task = new TimerTask() { @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode()); - result = prime * result + ((queueId == null) ? 0 : queueId.hashCode()); - return result; - } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof QueueEntry)) { - return false; - } - QueueEntry other = (QueueEntry) obj; - if (nodeConnectorId == null) { - if (other.nodeConnectorId != null) { - return false; - } - } else if (!nodeConnectorId.equals(other.nodeConnectorId)) { - return false; - } - if (queueId == null) { - if (other.queueId != null) { - return false; - } - } else if (!queueId.equals(other.queueId)) { - return false; - } - return true; + public void run() { + requestPeriodicStatistics(); + cleanStaleStatistics(); } + }; + + public NodeStatisticsHandler(final DataProviderService dps, final NodeKey nodeKey, + final OpendaylightFlowStatisticsService flowStatsService, + final OpendaylightFlowTableStatisticsService flowTableStatsService, + final OpendaylightGroupStatisticsService groupStatsService, + final OpendaylightMeterStatisticsService meterStatsService, + final OpendaylightPortStatisticsService portStatsService, + final OpendaylightQueueStatisticsService queueStatsService) { + this.dps = Preconditions.checkNotNull(dps); + this.targetNodeKey = Preconditions.checkNotNull(nodeKey); + this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build(); + this.targetNodeRef = new NodeRef(targetNodeIdentifier); + + final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES); + + msgManager = new MultipartMessageManager(lifetimeNanos); + flowStats = new FlowStatsTracker(flowStatsService, this, lifetimeNanos); + flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this, lifetimeNanos); + groupDescStats = new GroupDescStatsTracker(groupStatsService, this, lifetimeNanos); + groupStats = new GroupStatsTracker(groupStatsService, this, lifetimeNanos); + meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this, lifetimeNanos); + meterStats = new MeterStatsTracker(meterStatsService, this, lifetimeNanos); + nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this, lifetimeNanos); + queueStats = new QueueStatsTracker(queueStatsService, this, lifetimeNanos); } public NodeKey getTargetNodeKey() { return targetNodeKey; } - public synchronized void updateGroupDescStats(List list){ - final Long expiryTime = getExpiryTime(); - final DataModificationTransaction trans = statisticsProvider.startChange(); - - for (GroupDescStats groupDescStats : list) { - GroupBuilder groupBuilder = new GroupBuilder(); - GroupKey groupKey = new GroupKey(groupDescStats.getGroupId()); - groupBuilder.setKey(groupKey); - - InstanceIdentifier groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Group.class,groupKey).toInstance(); + @Override + public InstanceIdentifier getNodeIdentifier() { + return targetNodeIdentifier; + } - NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder(); - GroupDescBuilder stats = new GroupDescBuilder(); - stats.fieldsFrom(groupDescStats); - groupDesc.setGroupDesc(stats.build()); + @Override + public NodeRef getNodeRef() { + return targetNodeRef; + } - //Update augmented data - groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build()); + @Override + public DataModificationTransaction startDataModification() { + return dps.beginTransaction(); + } - trans.putOperationalData(groupRef, groupBuilder.build()); - this.groupDescStatsUpdate.put(groupDescStats, expiryTime); + public synchronized void updateGroupDescStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + groupDescStats.updateStats(list); } - - trans.commit(); } - - public synchronized void updateGroupStats(List list) { - final DataModificationTransaction trans = statisticsProvider.startChange(); - - for(GroupStats groupStats : list) { - GroupBuilder groupBuilder = new GroupBuilder(); - GroupKey groupKey = new GroupKey(groupStats.getGroupId()); - groupBuilder.setKey(groupKey); - - InstanceIdentifier groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Group.class,groupKey).toInstance(); - - NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder(); - GroupStatisticsBuilder stats = new GroupStatisticsBuilder(); - stats.fieldsFrom(groupStats); - groupStatisticsBuilder.setGroupStatistics(stats.build()); - - //Update augmented data - groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build()); - trans.putOperationalData(groupRef, groupBuilder.build()); - - // FIXME: should we be tracking this data? + public synchronized void updateGroupStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + groupStats.updateStats(list); } - - trans.commit(); } - public synchronized void updateMeterConfigStats(List list) { - final Long expiryTime = getExpiryTime(); - final DataModificationTransaction trans = statisticsProvider.startChange(); - - for(MeterConfigStats meterConfigStats : list) { - MeterBuilder meterBuilder = new MeterBuilder(); - MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId()); - meterBuilder.setKey(meterKey); - - InstanceIdentifier meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Meter.class,meterKey).toInstance(); - - NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder(); - MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder(); - stats.fieldsFrom(meterConfigStats); - meterConfig.setMeterConfigStats(stats.build()); - - //Update augmented data - meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build()); - - trans.putOperationalData(meterRef, meterBuilder.build()); - this.meterConfigStatsUpdate.put(meterConfigStats, expiryTime); + public synchronized void updateMeterConfigStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + meterConfigStats.updateStats(list); } - - trans.commit(); } - - public synchronized void updateMeterStats(List list) { - final DataModificationTransaction trans = statisticsProvider.startChange(); - - for(MeterStats meterStats : list) { - MeterBuilder meterBuilder = new MeterBuilder(); - MeterKey meterKey = new MeterKey(meterStats.getMeterId()); - meterBuilder.setKey(meterKey); - - InstanceIdentifier meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Meter.class,meterKey).toInstance(); - - NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder(); - MeterStatisticsBuilder stats = new MeterStatisticsBuilder(); - stats.fieldsFrom(meterStats); - meterStatsBuilder.setMeterStatistics(stats.build()); - - //Update augmented data - meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build()); - trans.putOperationalData(meterRef, meterBuilder.build()); - - // FIXME: should we be tracking this data? + public synchronized void updateMeterStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + meterStats.updateStats(list); } - - trans.commit(); } - public synchronized void updateQueueStats(List list) { - final Long expiryTime = getExpiryTime(); - final DataModificationTransaction trans = statisticsProvider.startChange(); - - for (QueueIdAndStatisticsMap swQueueStats : list) { - - QueueEntry queueEntry = new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId()); - - FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder(); - - FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder(); - - queueStatisticsBuilder.fieldsFrom(swQueueStats); - - queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build()); - - InstanceIdentifier queueRef - = InstanceIdentifier.builder(Nodes.class) - .child(Node.class, targetNodeKey) - .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId())) - .augmentation(FlowCapableNodeConnector.class) - .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance(); - - QueueBuilder queueBuilder = new QueueBuilder(); - FlowCapableNodeConnectorQueueStatisticsData qsd = queueStatisticsDataBuilder.build(); - queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, qsd); - queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId())); - - logger.debug("Augmenting queue statistics {} of queue {} to port {}", - qsd, - swQueueStats.getQueueId(), - swQueueStats.getNodeConnectorId()); - - trans.putOperationalData(queueRef, queueBuilder.build()); - this.queuesStatsUpdate.put(queueEntry, expiryTime); + public synchronized void updateQueueStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + queueStats.updateStats(list); } - - trans.commit(); } - public synchronized void updateFlowTableStats(List list) { - final DataModificationTransaction trans = statisticsProvider.startChange(); - - for (FlowTableAndStatisticsMap ftStats : list) { - - InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) - .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance(); - - FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder(); - - FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder(); - statisticsBuilder.setActiveFlows(ftStats.getActiveFlows()); - statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp()); - statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched()); - - final FlowTableStatistics stats = statisticsBuilder.build(); - statisticsDataBuilder.setFlowTableStatistics(stats); - - logger.debug("Augment flow table statistics: {} for table {} on Node {}", - stats,ftStats.getTableId(), targetNodeKey); - - TableBuilder tableBuilder = new TableBuilder(); - tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue())); - tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build()); - trans.putOperationalData(tableRef, tableBuilder.build()); - - // FIXME: should we be tracking this data? + public synchronized void updateFlowTableStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + flowTableStats.updateStats(list); } - - trans.commit(); } - public synchronized void updateNodeConnectorStats(List list) { - final DataModificationTransaction trans = statisticsProvider.startChange(); - - for(NodeConnectorStatisticsAndPortNumberMap portStats : list) { - - FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder - = new FlowCapableNodeConnectorStatisticsBuilder(); - statisticsBuilder.setBytes(portStats.getBytes()); - statisticsBuilder.setCollisionCount(portStats.getCollisionCount()); - statisticsBuilder.setDuration(portStats.getDuration()); - statisticsBuilder.setPackets(portStats.getPackets()); - statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError()); - statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops()); - statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors()); - statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError()); - statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError()); - statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops()); - statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors()); - - //Augment data to the node-connector - FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder = - new FlowCapableNodeConnectorStatisticsDataBuilder(); - - statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build()); - - InstanceIdentifier nodeConnectorRef = InstanceIdentifier.builder(Nodes.class) - .child(Node.class, targetNodeKey) - .child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance(); - - // FIXME: can we bypass this read? - NodeConnector nodeConnector = (NodeConnector)trans.readOperationalData(nodeConnectorRef); - if(nodeConnector != null){ - final FlowCapableNodeConnectorStatisticsData stats = statisticsDataBuilder.build(); - logger.debug("Augmenting port statistics {} to port {}",stats,nodeConnectorRef.toString()); - NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder(); - nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats); - trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build()); - } - - // FIXME: should we be tracking this data? + public synchronized void updateNodeConnectorStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + nodeConnectorStats.updateStats(list); } - - trans.commit(); } - public synchronized void updateAggregateFlowStats(Short tableId, AggregateFlowStatistics flowStats) { + public synchronized void updateAggregateFlowStats(TransactionAware transaction, Boolean more, AggregateFlowStatistics flowStats) { + final Short tableId = msgManager.isExpectedTableTransaction(transaction, more); if (tableId != null) { - final DataModificationTransaction trans = statisticsProvider.startChange(); - - + final DataModificationTransaction trans = dps.beginTransaction(); InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); @@ -483,13 +199,18 @@ public class NodeStatisticsHandler { tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build()); trans.putOperationalData(tableRef, tableBuilder.build()); - // FIXME: should we be tracking this data? trans.commit(); } } + public synchronized void updateFlowStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + flowStats.updateStats(list); + } + } + public synchronized void updateGroupFeatures(GroupFeatures notification) { - final DataModificationTransaction trans = statisticsProvider.startChange(); + final DataModificationTransaction trans = dps.beginTransaction(); final NodeBuilder nodeData = new NodeBuilder(); nodeData.setKey(targetNodeKey); @@ -507,7 +228,7 @@ public class NodeStatisticsHandler { } public synchronized void updateMeterFeatures(MeterFeatures features) { - final DataModificationTransaction trans = statisticsProvider.startChange(); + final DataModificationTransaction trans = dps.beginTransaction(); final NodeBuilder nodeData = new NodeBuilder(); nodeData.setKey(targetNodeKey); @@ -524,254 +245,82 @@ public class NodeStatisticsHandler { trans.commit(); } - public synchronized void updateFlowStats(List list) { - final Long expiryTime = getExpiryTime(); - final DataModificationTransaction trans = statisticsProvider.startChange(); - - for(FlowAndStatisticsMapList map : list) { - short tableId = map.getTableId(); - boolean foundOriginalFlow = false; - - FlowBuilder flowBuilder = new FlowBuilder(); - - FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder(); - - FlowBuilder flow = new FlowBuilder(); - flow.setContainerName(map.getContainerName()); - flow.setBufferId(map.getBufferId()); - flow.setCookie(map.getCookie()); - flow.setCookieMask(map.getCookieMask()); - flow.setFlags(map.getFlags()); - flow.setFlowName(map.getFlowName()); - flow.setHardTimeout(map.getHardTimeout()); - if(map.getFlowId() != null) - flow.setId(new FlowId(map.getFlowId().getValue())); - flow.setIdleTimeout(map.getIdleTimeout()); - flow.setInstallHw(map.isInstallHw()); - flow.setInstructions(map.getInstructions()); - if(map.getFlowId()!= null) - flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue()))); - flow.setMatch(map.getMatch()); - flow.setOutGroup(map.getOutGroup()); - flow.setOutPort(map.getOutPort()); - flow.setPriority(map.getPriority()); - flow.setStrict(map.isStrict()); - flow.setTableId(tableId); - - Flow flowRule = flow.build(); - - FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder(); - stats.setByteCount(map.getByteCount()); - stats.setPacketCount(map.getPacketCount()); - stats.setDuration(map.getDuration()); - - GenericStatistics flowStats = stats.build(); - - //Augment the data to the flow node - - FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder(); - flowStatistics.setByteCount(flowStats.getByteCount()); - flowStatistics.setPacketCount(flowStats.getPacketCount()); - flowStatistics.setDuration(flowStats.getDuration()); - flowStatistics.setContainerName(map.getContainerName()); - flowStatistics.setBufferId(map.getBufferId()); - flowStatistics.setCookie(map.getCookie()); - flowStatistics.setCookieMask(map.getCookieMask()); - flowStatistics.setFlags(map.getFlags()); - flowStatistics.setFlowName(map.getFlowName()); - flowStatistics.setHardTimeout(map.getHardTimeout()); - flowStatistics.setIdleTimeout(map.getIdleTimeout()); - flowStatistics.setInstallHw(map.isInstallHw()); - flowStatistics.setInstructions(map.getInstructions()); - flowStatistics.setMatch(map.getMatch()); - flowStatistics.setOutGroup(map.getOutGroup()); - flowStatistics.setOutPort(map.getOutPort()); - flowStatistics.setPriority(map.getPriority()); - flowStatistics.setStrict(map.isStrict()); - flowStatistics.setTableId(tableId); - - flowStatisticsData.setFlowStatistics(flowStatistics.build()); - - logger.debug("Flow : {}",flowRule.toString()); - logger.debug("Statistics to augment : {}",flowStatistics.build().toString()); - - InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) - .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); + public synchronized void cleanStaleStatistics() { + final DataModificationTransaction trans = dps.beginTransaction(); + final long now = System.nanoTime(); - Table table= (Table)trans.readConfigurationData(tableRef); - - //TODO: Not a good way to do it, need to figure out better way. - //TODO: major issue in any alternate approach is that flow key is incrementally assigned - //to the flows stored in data store. - // Augment same statistics to all the matching masked flow - if(table != null){ - - for(Flow existingFlow : table.getFlow()){ - logger.debug("Existing flow in data store : {}",existingFlow.toString()); - if(FlowComparator.flowEquals(flowRule,existingFlow)){ - InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,existingFlow.getKey()).toInstance(); - flowBuilder.setKey(existingFlow.getKey()); - flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - logger.debug("Found matching flow in the datastore, augmenting statistics"); - foundOriginalFlow = true; - // Update entry with timestamp of latest response - flow.setKey(existingFlow.getKey()); - FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build()); - flowStatsUpdate.put(flowStatsEntry, expiryTime); - - trans.putOperationalData(flowRef, flowBuilder.build()); - } - } - } - - table = (Table)trans.readOperationalData(tableRef); - if(!foundOriginalFlow && table != null){ - - for(Flow existingFlow : table.getFlow()){ - FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class); - if(augmentedflowStatisticsData != null){ - FlowBuilder existingOperationalFlow = new FlowBuilder(); - existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics()); - logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString()); - if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){ - InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,existingFlow.getKey()).toInstance(); - flowBuilder.setKey(existingFlow.getKey()); - flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics"); - foundOriginalFlow = true; - - // Update entry with timestamp of latest response - flow.setKey(existingFlow.getKey()); - FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build()); - flowStatsUpdate.put(flowStatsEntry, expiryTime); - trans.putOperationalData(flowRef, flowBuilder.build()); - break; - } - } - } - } - if(!foundOriginalFlow){ - String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter); - this.unaccountedFlowsCounter++; - FlowKey newFlowKey = new FlowKey(new FlowId(flowKey)); - InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,newFlowKey).toInstance(); - flowBuilder.setKey(newFlowKey); - flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow", - flowBuilder.build()); - - // Update entry with timestamp of latest response - flow.setKey(newFlowKey); - FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build()); - flowStatsUpdate.put(flowStatsEntry, expiryTime); - trans.putOperationalData(flowRef, flowBuilder.build()); - } - } + flowStats.cleanup(trans, now); + groupDescStats.cleanup(trans, now); + groupStats.cleanup(trans, now); + meterConfigStats.cleanup(trans, now); + meterStats.cleanup(trans, now); + nodeConnectorStats.cleanup(trans, now); + queueStats.cleanup(trans, now); + msgManager.cleanStaleTransactionIds(); trans.commit(); } - private static Long getExpiryTime(){ - final long now = System.nanoTime(); - return now + TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_THREAD_EXECUTION_TIME * NUMBER_OF_WAIT_CYCLES); - } + public synchronized void requestPeriodicStatistics() { + logger.debug("Send requests for statistics collection to node : {}", targetNodeKey); - public synchronized void cleanStaleStatistics(){ - final DataModificationTransaction trans = this.statisticsProvider.startChange(); - final long now = System.nanoTime(); + flowTableStats.request(); - //Clean stale statistics related to group - for (Iterator> it = this.groupDescStatsUpdate.entrySet().iterator();it.hasNext();){ - Entry e = it.next(); - if (now > e.getValue()) { - cleanGroupStatsFromDataStore(trans, e.getKey()); - it.remove(); - } + // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest() + // comes back -- we do not have any tables anyway. + final Collection tables = flowTableStats.getTables(); + logger.debug("Node {} supports {} table(s)", targetNodeKey, tables.size()); + for (final TableKey key : tables) { + logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), targetNodeKey); + flowStats.requestAggregateFlows(key); } - //Clean stale statistics related to meter - for (Iterator> it = this.meterConfigStatsUpdate.entrySet().iterator();it.hasNext();){ - Entry e = it.next(); - if (now > e.getValue()) { - cleanMeterStatsFromDataStore(trans, e.getKey()); - it.remove(); - } - } + flowStats.requestAllFlowsAllTables(); + nodeConnectorStats.request(); + groupStats.request(); + groupDescStats.request(); + meterStats.request(); + meterConfigStats.request(); + queueStats.request(); + } - //Clean stale statistics related to flow - for (Iterator> it = this.flowStatsUpdate.entrySet().iterator();it.hasNext();){ - Entry e = it.next(); - if (now > e.getValue()) { - cleanFlowStatsFromDataStore(trans, e.getKey()); - it.remove(); - } - } + public synchronized void start(final Timer timer) { + flowStats.start(dps); + groupDescStats.start(dps); + groupStats.start(dps); + meterConfigStats.start(dps); + meterStats.start(dps); + queueStats.start(dps); - //Clean stale statistics related to queue - for (Iterator> it = this.queuesStatsUpdate.entrySet().iterator();it.hasNext();){ - Entry e = it.next(); - if (now > e.getValue()) { - cleanQueueStatsFromDataStore(trans, e.getKey()); - it.remove(); - } - } + timer.schedule(task, (long) (Math.random() * FIRST_COLLECTION_MILLIS), STATS_COLLECTION_MILLIS); - trans.commit(); - } + logger.debug("Statistics handler for node started with base interval {}ms", STATS_COLLECTION_MILLIS); - private void cleanQueueStatsFromDataStore(DataModificationTransaction trans, QueueEntry queueEntry) { - InstanceIdentifier queueRef - = InstanceIdentifier.builder(Nodes.class) - .child(Node.class, this.targetNodeKey) - .child(NodeConnector.class, new NodeConnectorKey(queueEntry.getNodeConnectorId())) - .augmentation(FlowCapableNodeConnector.class) - .child(Queue.class, new QueueKey(queueEntry.getQueueId())) - .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance(); - trans.removeOperationalData(queueRef); + requestPeriodicStatistics(); } - private void cleanFlowStatsFromDataStore(DataModificationTransaction trans, FlowEntry flowEntry) { - InstanceIdentifier flowRef - = InstanceIdentifier.builder(Nodes.class).child(Node.class, this.targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(flowEntry.getTableId())) - .child(Flow.class,flowEntry.getFlow().getKey()) - .augmentation(FlowStatisticsData.class).toInstance(); - trans.removeOperationalData(flowRef); + @Override + public synchronized void close() { + task.cancel(); + flowStats.close(); + groupDescStats.close(); + groupStats.close(); + meterConfigStats.close(); + meterStats.close(); + queueStats.close(); + + logger.debug("Statistics handler for {} shut down", targetNodeKey.getId()); } - private void cleanMeterStatsFromDataStore(DataModificationTransaction trans, MeterConfigStats meterConfigStats) { - InstanceIdentifierBuilder meterRef - = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Meter.class,new MeterKey(meterConfigStats.getMeterId())); - - InstanceIdentifier nodeMeterConfigStatsAugmentation = meterRef.augmentation(NodeMeterConfigStats.class).toInstance(); - trans.removeOperationalData(nodeMeterConfigStatsAugmentation); - - InstanceIdentifier nodeMeterStatisticsAugmentation = meterRef.augmentation(NodeMeterStatistics.class).toInstance(); - trans.removeOperationalData(nodeMeterStatisticsAugmentation); + @Override + public void registerTransaction(TransactionId id) { + msgManager.recordExpectedTransaction(id); + logger.debug("Transaction {} for node {} sent successfully", id, targetNodeKey); } - private void cleanGroupStatsFromDataStore(DataModificationTransaction trans, GroupDescStats groupDescStats) { - InstanceIdentifierBuilder groupRef - = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Group.class,new GroupKey(groupDescStats.getGroupId())); - - InstanceIdentifier nodeGroupDescStatsAugmentation = groupRef.augmentation(NodeGroupDescStats.class).toInstance(); - trans.removeOperationalData(nodeGroupDescStatsAugmentation); - - InstanceIdentifier nodeGroupStatisticsAugmentation = groupRef.augmentation(NodeGroupStatistics.class).toInstance(); - trans.removeOperationalData(nodeGroupStatisticsAugmentation); + @Override + public void registerTableTransaction(final TransactionId id, final Short table) { + msgManager.recordExpectedTableTransaction(id, table); + logger.debug("Transaction {} for node {} table {} sent successfully", id, targetNodeKey, table); } } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java new file mode 100644 index 0000000000..d1f2529de8 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java @@ -0,0 +1,62 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; + +final class QueueStatsEntry { + private final NodeConnectorId nodeConnectorId; + private final QueueId queueId; + public QueueStatsEntry(NodeConnectorId ncId, QueueId queueId){ + this.nodeConnectorId = ncId; + this.queueId = queueId; + } + public NodeConnectorId getNodeConnectorId() { + return nodeConnectorId; + } + public QueueId getQueueId() { + return queueId; + } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode()); + result = prime * result + ((queueId == null) ? 0 : queueId.hashCode()); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof QueueStatsEntry)) { + return false; + } + QueueStatsEntry other = (QueueStatsEntry) obj; + if (nodeConnectorId == null) { + if (other.nodeConnectorId != null) { + return false; + } + } else if (!nodeConnectorId.equals(other.nodeConnectorId)) { + return false; + } + if (queueId == null) { + if (other.queueId != null) { + return false; + } + } else if (!queueId.equals(other.queueId)) { + return false; + } + return true; + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java new file mode 100644 index 0000000000..f187c7082e --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java @@ -0,0 +1,154 @@ +/* + * Copyright IBM Corporation, 2013. 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.md.statistics.manager; + +import java.util.Map.Entry; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class QueueStatsTracker extends AbstractListeningStatsTracker { + private static final Logger logger = LoggerFactory.getLogger(QueueStatsTracker.class); + private final OpendaylightQueueStatisticsService queueStatsService; + + QueueStatsTracker(OpendaylightQueueStatisticsService queueStatsService, final FlowCapableContext context, long lifetimeNanos) { + super(context, lifetimeNanos); + this.queueStatsService = queueStatsService; + } + + @Override + protected void cleanupSingleStat(DataModificationTransaction trans, QueueStatsEntry item) { + InstanceIdentifier queueRef + = getNodeIdentifierBuilder().child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId())) + .augmentation(FlowCapableNodeConnector.class) + .child(Queue.class, new QueueKey(item.getQueueId())) + .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).build(); + trans.removeOperationalData(queueRef); + } + + @Override + protected QueueStatsEntry updateSingleStat(DataModificationTransaction trans, QueueIdAndStatisticsMap item) { + + QueueStatsEntry queueEntry = new QueueStatsEntry(item.getNodeConnectorId(), item.getQueueId()); + + FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder(); + + FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder(); + + queueStatisticsBuilder.fieldsFrom(item); + + queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build()); + + InstanceIdentifier queueRef = getNodeIdentifierBuilder().child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId())) + .augmentation(FlowCapableNodeConnector.class) + .child(Queue.class, new QueueKey(item.getQueueId())).toInstance(); + + QueueBuilder queueBuilder = new QueueBuilder(); + FlowCapableNodeConnectorQueueStatisticsData qsd = queueStatisticsDataBuilder.build(); + queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, qsd); + queueBuilder.setKey(new QueueKey(item.getQueueId())); + + logger.debug("Augmenting queue statistics {} of queue {} to port {}", + qsd, + item.getQueueId(), + item.getNodeConnectorId()); + + trans.putOperationalData(queueRef, queueBuilder.build()); + return queueEntry; + } + + public void request() { + if (queueStatsService != null) { + GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder(); + input.setNode(getNodeRef()); + + requestHelper(queueStatsService.getAllQueuesStatisticsFromAllPorts(input.build())); + } + } + + public void request(NodeConnectorId nodeConnectorId, QueueId queueId) { + if (queueStatsService != null) { + GetQueueStatisticsFromGivenPortInputBuilder input = new GetQueueStatisticsFromGivenPortInputBuilder(); + + input.setNode(getNodeRef()); + input.setNodeConnectorId(nodeConnectorId); + input.setQueueId(queueId); + + requestHelper(queueStatsService.getQueueStatisticsFromGivenPort(input.build())); + } + } + + @Override + public void onDataChanged(DataChangeEvent, DataObject> change) { + for (Entry, DataObject> e : change.getCreatedConfigurationData().entrySet()) { + if (Queue.class.equals(e.getKey().getTargetType())) { + final Queue queue = (Queue) e.getValue(); + final NodeConnectorKey key = e.getKey().firstKeyOf(NodeConnector.class, NodeConnectorKey.class); + logger.debug("Key {} triggered request for connector {} queue {}", key.getId(), queue.getQueueId()); + request(key.getId(), queue.getQueueId()); + } else { + logger.debug("Ignoring key {}", e.getKey()); + } + } + + final DataModificationTransaction trans = startTransaction(); + for (InstanceIdentifier key : change.getRemovedConfigurationData()) { + if (Queue.class.equals(key.getTargetType())) { + @SuppressWarnings("unchecked") + final InstanceIdentifier queue = (InstanceIdentifier)key; + final InstanceIdentifier del = InstanceIdentifier.builder(queue) + .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).build(); + logger.debug("Key {} triggered remove of augmentation {}", key, del); + + trans.removeOperationalData(del); + } + } + trans.commit(); + } + + @Override + protected InstanceIdentifier listenPath() { + return getNodeIdentifierBuilder().child(NodeConnector.class) + .augmentation(FlowCapableNodeConnector.class).child(Queue.class).build(); + } + + @Override + protected String statName() { + return "Queue"; + } + + @Override + public void start(final DataBrokerService dbs) { + if (queueStatsService == null) { + logger.debug("No Queue Statistics service, not subscribing to queues on node {}", getNodeIdentifier()); + return; + } + + super.start(dbs); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java new file mode 100644 index 0000000000..308c6ddebe --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java @@ -0,0 +1,27 @@ +/* + * 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.md.statistics.manager; + +import java.util.Collection; + +import org.opendaylight.yangtools.yang.common.RpcError; + +final class RPCFailedException extends RuntimeException { + private static final long serialVersionUID = 1L; + private final Collection errors; + + public RPCFailedException(final String message, final Collection errors) { + super(message); + this.errors = errors; + } + + @Override + public String toString() { + return "RPCFailedException [errors=" + errors + ", message=" + getMessage() + ']'; + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java index 155815dc88..bd9f96c875 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java @@ -44,7 +44,6 @@ public class StatisticsListener implements OpendaylightGroupStatisticsListener, private final static Logger sucLogger = LoggerFactory.getLogger(StatisticsListener.class); private final StatisticsProvider statisticsManager; - private final MultipartMessageManager messageManager; /** * default ctor @@ -52,56 +51,37 @@ public class StatisticsListener implements OpendaylightGroupStatisticsListener, */ public StatisticsListener(final StatisticsProvider manager){ this.statisticsManager = manager; - this.messageManager = this.statisticsManager.getMultipartMessageManager(); } @Override public void onMeterConfigStatsUpdated(final MeterConfigStatsUpdated notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - //Add statistics to local cache final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); if (handler != null) { - handler.updateMeterConfigStats(notification.getMeterConfigStats()); + handler.updateMeterConfigStats(notification, notification.isMoreReplies(), notification.getMeterConfigStats()); } } @Override public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - //Add statistics to local cache final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); if (handler != null) { - handler.updateMeterStats(notification.getMeterStats()); + handler.updateMeterStats(notification, notification.isMoreReplies(), notification.getMeterStats()); } } @Override public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId()); if (handler != null) { - handler.updateGroupDescStats(notification.getGroupDescStats()); + handler.updateGroupDescStats(notification, notification.isMoreReplies(), notification.getGroupDescStats()); } } @Override public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId()); if (handler != null) { - handler.updateGroupStats(notification.getGroupStats()); + handler.updateGroupStats(notification, notification.isMoreReplies(), notification.getGroupStats()); } } @@ -123,65 +103,42 @@ public class StatisticsListener implements OpendaylightGroupStatisticsListener, @Override public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - sucLogger.debug("Received flow stats update : {}",notification.toString()); final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId()); if (sna != null) { - sna.updateFlowStats(notification.getFlowAndStatisticsMapList()); + sna.updateFlowStats(notification, notification.isMoreReplies(), notification.getFlowAndStatisticsMapList()); } } @Override public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); if (handler != null) { - final Short tableId = messageManager.getTableIdForTxId(notification.getId(),notification.getTransactionId()); - handler.updateAggregateFlowStats(tableId, notification); + handler.updateAggregateFlowStats(notification, notification.isMoreReplies(), notification); } } @Override public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); if (handler != null) { - handler.updateNodeConnectorStats(notification.getNodeConnectorStatisticsAndPortNumberMap()); + handler.updateNodeConnectorStats(notification, notification.isMoreReplies(), notification.getNodeConnectorStatisticsAndPortNumberMap()); } } @Override public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); if (handler != null) { - handler.updateFlowTableStats(notification.getFlowTableAndStatisticsMap()); + handler.updateFlowTableStats(notification, notification.isMoreReplies(), notification.getFlowTableAndStatisticsMap()); } } @Override public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - //Add statistics to local cache final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); if (handler != null) { - handler.updateQueueStats(notification.getQueueIdAndStatisticsMap()); + handler.updateQueueStats(notification, notification.isMoreReplies(), notification.getQueueIdAndStatisticsMap()); } } } - diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java index b59482e96b..5bcbef119a 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java @@ -11,7 +11,6 @@ package org.opendaylight.controller.md.statistics.manager; import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.osgi.framework.BundleContext; @@ -20,12 +19,11 @@ public class StatisticsManagerActivator extends AbstractBindingAwareProvider { @Override public void onSessionInitiated(ProviderContext session) { - final DataBrokerService dbs = session.getSALService(DataBrokerService.class); final DataProviderService dps = session.getSALService(DataProviderService.class); final NotificationProviderService nps = session.getSALService(NotificationProviderService.class); statsProvider = new StatisticsProvider(dps); - statsProvider.start(dbs, nps, session); + statsProvider.start(nps, session); } @Override diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java index ab5d20a951..892d304daa 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java @@ -7,68 +7,30 @@ */ package org.opendaylight.controller.md.statistics.manager; -import java.util.ArrayList; -import java.util.List; +import java.util.Collection; +import java.util.Timer; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import org.eclipse.xtext.xbase.lib.Exceptions; -import org.opendaylight.controller.md.statistics.manager.MultipartMessageManager.StatsRequestType; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; 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.DataModificationTransaction; +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; -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.table.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; 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.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService; +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.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.NotificationListener; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -87,17 +49,12 @@ import com.google.common.base.Preconditions; * */ public class StatisticsProvider implements AutoCloseable { - public static final int STATS_THREAD_EXECUTION_TIME= 15000; - private static final Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class); - private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager(); - private final InstanceIdentifier nodesIdentifier = InstanceIdentifier.builder(Nodes.class).toInstance(); + private final ConcurrentMap handlers = new ConcurrentHashMap<>(); + private final Timer timer = new Timer("statistics-manager", true); private final DataProviderService dps; - //Local caching of stats - private final ConcurrentMap statisticsCache = new ConcurrentHashMap<>(); - private OpendaylightGroupStatisticsService groupStatsService; private OpendaylightMeterStatisticsService meterStatsService; @@ -110,33 +67,19 @@ public class StatisticsProvider implements AutoCloseable { private OpendaylightQueueStatisticsService queueStatsService; - private StatisticsUpdateHandler statsUpdateHandler; - - private Thread statisticsRequesterThread; - - private Thread statisticsAgerThread; - - public StatisticsProvider(final DataProviderService dataService) { this.dps = Preconditions.checkNotNull(dataService); } - public MultipartMessageManager getMultipartMessageManager() { - return multipartMessageManager; - } - private final StatisticsListener updateCommiter = new StatisticsListener(StatisticsProvider.this); private Registration listenerRegistration; - public void start(final DataBrokerService dbs, final NotificationProviderService nps, final RpcConsumerRegistry rpcRegistry) { - - this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter); + private ListenerRegistration flowCapableTrackerRegistration; - statsUpdateHandler = new StatisticsUpdateHandler(StatisticsProvider.this); - registerDataStoreUpdateListener(dbs); + public void start(final NotificationProviderService nps, final RpcConsumerRegistry rpcRegistry) { - // Get Group/Meter statistics service instance + // Get Group/Meter statistics service instances groupStatsService = rpcRegistry.getRpcService(OpendaylightGroupStatisticsService.class); meterStatsService = rpcRegistry.getRpcService(OpendaylightMeterStatisticsService.class); flowStatsService = rpcRegistry.getRpcService(OpendaylightFlowStatisticsService.class); @@ -144,310 +87,19 @@ public class StatisticsProvider implements AutoCloseable { flowTableStatsService = rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class); queueStatsService = rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class); - statisticsRequesterThread = new Thread( new Runnable(){ - - @Override - public void run() { - while(true){ - try { - statsRequestSender(); - - Thread.sleep(STATS_THREAD_EXECUTION_TIME); - }catch (Exception e){ - spLogger.error("Exception occurred while sending stats request : {}",e); - } - } - } - }); - - spLogger.debug("Statistics requester thread started with timer interval : {}",STATS_THREAD_EXECUTION_TIME); - - statisticsRequesterThread.start(); - - statisticsAgerThread = new Thread( new Runnable(){ - - @Override - public void run() { - while(true){ - try { - for(NodeStatisticsHandler nodeStatisticsAger : statisticsCache.values()){ - nodeStatisticsAger.cleanStaleStatistics(); - } - multipartMessageManager.cleanStaleTransactionIds(); - - Thread.sleep(STATS_THREAD_EXECUTION_TIME); - }catch (Exception e){ - spLogger.error("Exception occurred while sending stats request : {}",e); - } - } - } - }); - - spLogger.debug("Statistics ager thread started with timer interval : {}",STATS_THREAD_EXECUTION_TIME); + // Start receiving notifications + this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter); - statisticsAgerThread.start(); + // Register for switch connect/disconnect notifications + final InstanceIdentifier fcnId = InstanceIdentifier.builder(Nodes.class) + .child(Node.class).augmentation(FlowCapableNode.class).build(); + spLogger.debug("Registering FlowCapable tracker to {}", fcnId); + this.flowCapableTrackerRegistration = dps.registerDataChangeListener(fcnId, + new FlowCapableTracker(this, fcnId)); spLogger.info("Statistics Provider started."); } - private void registerDataStoreUpdateListener(DataBrokerService dbs) { - //Register for Node updates - InstanceIdentifier pathNode = InstanceIdentifier.builder(Nodes.class) - .child(Node.class).toInstance(); - dbs.registerDataChangeListener(pathNode, statsUpdateHandler); - - //Register for flow updates - InstanceIdentifier pathFlow = InstanceIdentifier.builder(Nodes.class).child(Node.class) - .augmentation(FlowCapableNode.class) - .child(Table.class) - .child(Flow.class).toInstance(); - dbs.registerDataChangeListener(pathFlow, statsUpdateHandler); - - //Register for meter updates - InstanceIdentifier pathMeter = InstanceIdentifier.builder(Nodes.class).child(Node.class) - .augmentation(FlowCapableNode.class) - .child(Meter.class).toInstance(); - - dbs.registerDataChangeListener(pathMeter, statsUpdateHandler); - - //Register for group updates - InstanceIdentifier pathGroup = InstanceIdentifier.builder(Nodes.class).child(Node.class) - .augmentation(FlowCapableNode.class) - .child(Group.class).toInstance(); - dbs.registerDataChangeListener(pathGroup, statsUpdateHandler); - - //Register for queue updates - InstanceIdentifier pathQueue = InstanceIdentifier.builder(Nodes.class).child(Node.class) - .child(NodeConnector.class) - .augmentation(FlowCapableNodeConnector.class) - .child(Queue.class).toInstance(); - dbs.registerDataChangeListener(pathQueue, statsUpdateHandler); - } - - protected DataModificationTransaction startChange() { - return dps.beginTransaction(); - } - - private void statsRequestSender(){ - - List targetNodes = getAllConnectedNodes(); - - if(targetNodes == null) - return; - - - for (Node targetNode : targetNodes){ - - if(targetNode.getAugmentation(FlowCapableNode.class) != null){ - sendStatisticsRequestsToNode(targetNode); - } - } - } - - public void sendStatisticsRequestsToNode(Node targetNode){ - - spLogger.debug("Send requests for statistics collection to node : {})",targetNode.getId()); - - InstanceIdentifier targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance(); - - NodeRef targetNodeRef = new NodeRef(targetInstanceId); - - try{ - if(flowStatsService != null){ - sendAggregateFlowsStatsFromAllTablesRequest(targetNode.getKey()); - sendAllFlowsStatsFromAllTablesRequest(targetNodeRef); - } - if(flowTableStatsService != null){ - sendAllFlowTablesStatisticsRequest(targetNodeRef); - } - if(portStatsService != null){ - sendAllNodeConnectorsStatisticsRequest(targetNodeRef); - } - if(groupStatsService != null){ - sendAllGroupStatisticsRequest(targetNodeRef); - sendGroupDescriptionRequest(targetNodeRef); - } - if(meterStatsService != null){ - sendAllMeterStatisticsRequest(targetNodeRef); - sendMeterConfigStatisticsRequest(targetNodeRef); - } - if(queueStatsService != null){ - sendAllQueueStatsFromAllNodeConnector (targetNodeRef); - } - }catch(Exception e){ - spLogger.error("Exception occured while sending statistics requests : {}", e); - } - } - - - public void sendAllFlowTablesStatisticsRequest(NodeRef targetNodeRef) throws InterruptedException, ExecutionException { - final GetFlowTablesStatisticsInputBuilder input = - new GetFlowTablesStatisticsInputBuilder(); - - input.setNode(targetNodeRef); - - Future> response = - flowTableStatsService.getFlowTablesStatistics(input.build()); - - this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNodeRef),response.get().getResult().getTransactionId() - , StatsRequestType.ALL_FLOW_TABLE); - - } - - public void sendAllFlowsStatsFromAllTablesRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ - final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input = - new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder(); - - input.setNode(targetNode); - - Future> response = - flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build()); - - this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() - , StatsRequestType.ALL_FLOW); - - } - - public void sendFlowStatsFromTableRequest(NodeRef targetNode,Flow flow) throws InterruptedException, ExecutionException{ - final GetFlowStatisticsFromFlowTableInputBuilder input = - new GetFlowStatisticsFromFlowTableInputBuilder(); - - input.setNode(targetNode); - input.fieldsFrom(flow); - - Future> response = - flowStatsService.getFlowStatisticsFromFlowTable(input.build()); - - this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() - , StatsRequestType.ALL_FLOW); - - } - - public void sendAggregateFlowsStatsFromAllTablesRequest(NodeKey targetNodeKey) throws InterruptedException, ExecutionException{ - - List tablesId = getTablesFromNode(targetNodeKey); - - if(tablesId.size() != 0){ - for(Short id : tablesId){ - - sendAggregateFlowsStatsFromTableRequest(targetNodeKey,id); - } - }else{ - spLogger.debug("No details found in data store for flow tables associated with Node {}",targetNodeKey); - } - } - - public void sendAggregateFlowsStatsFromTableRequest(NodeKey targetNodeKey,Short tableId) throws InterruptedException, ExecutionException{ - - spLogger.debug("Send aggregate stats request for flow table {} to node {}",tableId,targetNodeKey); - GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = - new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder(); - - input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance())); - input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(tableId)); - Future> response = - flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build()); - - multipartMessageManager.setTxIdAndTableIdMapEntry(targetNodeKey.getId(), response.get().getResult().getTransactionId(), tableId); - this.multipartMessageManager.addTxIdToRequestTypeEntry(targetNodeKey.getId(), response.get().getResult().getTransactionId() - , StatsRequestType.AGGR_FLOW); - } - - public void sendAllNodeConnectorsStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ - - final GetAllNodeConnectorsStatisticsInputBuilder input = new GetAllNodeConnectorsStatisticsInputBuilder(); - - input.setNode(targetNode); - - Future> response = - portStatsService.getAllNodeConnectorsStatistics(input.build()); - this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() - , StatsRequestType.ALL_PORT); - - } - - public void sendAllGroupStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ - - final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder(); - - input.setNode(targetNode); - - Future> response = - groupStatsService.getAllGroupStatistics(input.build()); - - this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() - , StatsRequestType.ALL_GROUP); - - } - - public void sendGroupDescriptionRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ - final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder(); - - input.setNode(targetNode); - - Future> response = - groupStatsService.getGroupDescription(input.build()); - - this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() - , StatsRequestType.GROUP_DESC); - - } - - public void sendAllMeterStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ - - GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder(); - - input.setNode(targetNode); - - Future> response = - meterStatsService.getAllMeterStatistics(input.build()); - - this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() - , StatsRequestType.ALL_METER);; - - } - - public void sendMeterConfigStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ - - GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder(); - - input.setNode(targetNode); - - Future> response = - meterStatsService.getAllMeterConfigStatistics(input.build()); - - this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() - , StatsRequestType.METER_CONFIG);; - - } - - public void sendAllQueueStatsFromAllNodeConnector(NodeRef targetNode) throws InterruptedException, ExecutionException { - GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder(); - - input.setNode(targetNode); - - Future> response = - queueStatsService.getAllQueuesStatisticsFromAllPorts(input.build()); - - this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() - , StatsRequestType.ALL_QUEUE_STATS);; - - } - - public void sendQueueStatsFromGivenNodeConnector(NodeRef targetNode,NodeConnectorId nodeConnectorId, QueueId queueId) throws InterruptedException, ExecutionException { - GetQueueStatisticsFromGivenPortInputBuilder input = new GetQueueStatisticsFromGivenPortInputBuilder(); - - input.setNode(targetNode); - input.setNodeConnectorId(nodeConnectorId); - input.setQueueId(queueId); - Future> response = - queueStatsService.getQueueStatisticsFromGivenPort(input.build()); - - this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() - , StatsRequestType.ALL_QUEUE_STATS);; - - } - /** * Get the handler for a particular node. * @@ -457,63 +109,61 @@ public class StatisticsProvider implements AutoCloseable { */ public final NodeStatisticsHandler getStatisticsHandler(final NodeId nodeId) { Preconditions.checkNotNull(nodeId); - NodeStatisticsHandler ager = statisticsCache.get(nodeId); - if (ager == null) { - ager = new NodeStatisticsHandler(this, new NodeKey(nodeId)); - statisticsCache.put(nodeId, ager); - } - - return ager; - } - - private List getAllConnectedNodes(){ - Nodes nodes = (Nodes) dps.readOperationalData(nodesIdentifier); - if(nodes == null) - return null; - - spLogger.debug("Number of connected nodes : {}",nodes.getNode().size()); - return nodes.getNode(); - } - - private List getTablesFromNode(NodeKey nodeKey){ - InstanceIdentifier nodesIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class,nodeKey).augmentation(FlowCapableNode.class).toInstance(); - - FlowCapableNode node = (FlowCapableNode)dps.readOperationalData(nodesIdentifier); - List tablesId = new ArrayList(); - if(node != null && node.getTable()!=null){ - spLogger.debug("Number of tables {} supported by node {}",node.getTable().size(),nodeKey); - for(Table table: node.getTable()){ - tablesId.add(table.getId()); - } + NodeStatisticsHandler handler = handlers.get(nodeId); + if (handler == null) { + spLogger.info("Attempted to get non-existing handler for {}", nodeId); } - return tablesId; - } - - @SuppressWarnings("unchecked") - private NodeId getNodeId(NodeRef nodeRef){ - InstanceIdentifier nodeII = (InstanceIdentifier) nodeRef.getValue(); - NodeKey nodeKey = InstanceIdentifier.keyOf(nodeII); - return nodeKey.getId(); + return handler; } - @SuppressWarnings("deprecation") @Override - public void close(){ - + public void close() { try { - spLogger.info("Statistics Provider stopped."); if (this.listenerRegistration != null) { - this.listenerRegistration.close(); + this.listenerRegistration = null; + } + if (this.flowCapableTrackerRegistration != null) { + this.flowCapableTrackerRegistration.close(); + this.flowCapableTrackerRegistration = null; + } + timer.cancel(); + } catch (Exception e) { + spLogger.warn("Failed to stop Statistics Provider completely", e); + } finally { + spLogger.info("Statistics Provider stopped."); + } + } - this.statisticsRequesterThread.destroy(); - - this.statisticsAgerThread.destroy(); + void startNodeHandlers(final Collection addedNodes) { + for (NodeKey key : addedNodes) { + if (handlers.containsKey(key.getId())) { + spLogger.warn("Attempted to start already-existing handler for {}, very strange", key.getId()); + continue; + } + final NodeStatisticsHandler h = new NodeStatisticsHandler(dps, key, + flowStatsService, flowTableStatsService, groupStatsService, + meterStatsService, portStatsService, queueStatsService); + final NodeStatisticsHandler old = handlers.putIfAbsent(key.getId(), h); + if (old == null) { + spLogger.debug("Started node handler for {}", key.getId()); + h.start(timer); + } else { + spLogger.debug("Prevented race on handler for {}", key.getId()); } - } catch (Throwable e) { - throw Exceptions.sneakyThrow(e); - } + } } + void stopNodeHandlers(final Collection removedNodes) { + for (NodeKey key : removedNodes) { + final NodeStatisticsHandler s = handlers.remove(key.getId()); + if (s != null) { + spLogger.debug("Stopping node handler for {}", key.getId()); + s.close(); + } else { + spLogger.warn("Attempted to remove non-existing handler for {}, very strange", key.getId()); + } + } + } } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java deleted file mode 100644 index acf182ad2b..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright IBM Corporation, 2013. 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.md.statistics.manager; - -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ExecutionException; - -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Following are two main responsibilities of the class - * 1) Listen for the create changes in config data store for tree nodes (Flow,Group,Meter,Queue) - * and send statistics request to the switch to fetch the statistics - * - * 2)Listen for the remove changes in config data store for tree nodes (Flow,Group,Meter,Queue) - * and remove the relative statistics data from operational data store. - * - * @author avishnoi@in.ibm.com - * - */ -public class StatisticsUpdateHandler implements DataChangeListener { - - private static final Logger suhLogger = LoggerFactory.getLogger(StatisticsUpdateHandler.class); - private final StatisticsProvider statisticsManager; - - public StatisticsUpdateHandler(final StatisticsProvider manager){ - this.statisticsManager = manager; - } - - @SuppressWarnings("unchecked") - @Override - public void onDataChanged(DataChangeEvent, DataObject> change) { - - Map, DataObject> nodeAdditions = change.getCreatedOperationalData(); - for (InstanceIdentifier dataObjectInstance : nodeAdditions.keySet()) { - DataObject dataObject = nodeAdditions.get(dataObjectInstance); - if(dataObject instanceof Node){ - - Node node = (Node) dataObject; - if(node.getAugmentation(FlowCapableNode.class) != null){ - this.statisticsManager.sendStatisticsRequestsToNode(node); - } - } - } - - Map, DataObject> additions = change.getCreatedConfigurationData(); - for (InstanceIdentifier dataObjectInstance : additions.keySet()) { - DataObject dataObject = additions.get(dataObjectInstance); - InstanceIdentifier nodeII = dataObjectInstance.firstIdentifierOf(Node.class); - NodeRef nodeRef = new NodeRef(nodeII); - if(dataObject instanceof Flow){ - Flow flow = (Flow) dataObject; - try { - this.statisticsManager.sendFlowStatsFromTableRequest(nodeRef, flow); - } catch (InterruptedException | ExecutionException e) { - suhLogger.warn("Following exception occured while sending flow statistics request newly added flow: {}", e); - } - } - if(dataObject instanceof Meter){ - try { - this.statisticsManager.sendMeterConfigStatisticsRequest(nodeRef); - } catch (InterruptedException | ExecutionException e) { - suhLogger.warn("Following exception occured while sending meter statistics request for newly added meter: {}", e); - } - } - if(dataObject instanceof Group){ - try { - this.statisticsManager.sendGroupDescriptionRequest(nodeRef); - } catch (InterruptedException | ExecutionException e) { - suhLogger.warn("Following exception occured while sending group description request for newly added group: {}", e); - } - } - if(dataObject instanceof Queue){ - Queue queue = (Queue) dataObject; - InstanceIdentifier nodeConnectorII = dataObjectInstance.firstIdentifierOf(NodeConnector.class); - NodeConnectorKey nodeConnectorKey = InstanceIdentifier.keyOf(nodeConnectorII); - try { - this.statisticsManager.sendQueueStatsFromGivenNodeConnector(nodeRef, nodeConnectorKey.getId(), queue.getQueueId()); - } catch (InterruptedException | ExecutionException e) { - suhLogger.warn("Following exception occured while sending queue statistics request for newly added group: {}", e); - } - } - } - - DataModificationTransaction it = this.statisticsManager.startChange(); - Set> removals = change.getRemovedConfigurationData(); - for (InstanceIdentifier dataObjectInstance : removals) { - DataObject dataObject = change.getOriginalConfigurationData().get(dataObjectInstance); - - if(dataObject instanceof Flow){ - InstanceIdentifier flowII = (InstanceIdentifier)dataObjectInstance; - InstanceIdentifier flowAugmentation = - InstanceIdentifier.builder(flowII).augmentation(FlowStatisticsData.class).toInstance(); - it.removeOperationalData(flowAugmentation); - } - if(dataObject instanceof Meter){ - InstanceIdentifier meterII = (InstanceIdentifier)dataObjectInstance; - - InstanceIdentifier nodeMeterConfigStatsAugmentation = - InstanceIdentifier.builder(meterII).augmentation(NodeMeterConfigStats.class).toInstance(); - it.removeOperationalData(nodeMeterConfigStatsAugmentation); - - InstanceIdentifier nodeMeterStatisticsAugmentation = - InstanceIdentifier.builder(meterII).augmentation(NodeMeterStatistics.class).toInstance(); - it.removeOperationalData(nodeMeterStatisticsAugmentation); - } - - if(dataObject instanceof Group){ - InstanceIdentifier groupII = (InstanceIdentifier)dataObjectInstance; - - InstanceIdentifier nodeGroupDescStatsAugmentation = - InstanceIdentifier.builder(groupII).augmentation(NodeGroupDescStats.class).toInstance(); - it.removeOperationalData(nodeGroupDescStatsAugmentation); - - InstanceIdentifier nodeGroupStatisticsAugmentation = - InstanceIdentifier.builder(groupII).augmentation(NodeGroupStatistics.class).toInstance(); - it.removeOperationalData(nodeGroupStatisticsAugmentation); - } - - if(dataObject instanceof Queue){ - InstanceIdentifier queueII = (InstanceIdentifier)dataObjectInstance; - - InstanceIdentifier nodeConnectorQueueStatisticsDataAugmentation = - InstanceIdentifier.builder(queueII).augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance(); - it.removeOperationalData(nodeConnectorQueueStatisticsDataAugmentation); - } - } - it.commit(); - } -} diff --git a/opendaylight/md-sal/topology-lldp-discovery/pom.xml b/opendaylight/md-sal/topology-lldp-discovery/pom.xml index 53cf2bd5c1..590e8ea91a 100644 --- a/opendaylight/md-sal/topology-lldp-discovery/pom.xml +++ b/opendaylight/md-sal/topology-lldp-discovery/pom.xml @@ -28,27 +28,22 @@ org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT org.opendaylight.controller.model model-flow-service - 1.1-SNAPSHOT org.opendaylight.controller.model model-flow-base - 1.1-SNAPSHOT org.opendaylight.controller.model model-flow-management - 1.1-SNAPSHOT org.opendaylight.controller.model model-inventory - 1.1-SNAPSHOT org.eclipse.xtend @@ -57,7 +52,6 @@ equinoxSDK381 org.eclipse.osgi - 3.8.1.v20120830-144521 commons-lang @@ -71,12 +65,10 @@ commons-codec commons-codec - 1.7 org.opendaylight.controller sal - 0.7.1-SNAPSHOT diff --git a/opendaylight/md-sal/topology-manager/pom.xml b/opendaylight/md-sal/topology-manager/pom.xml index 3c676c8d8f..525ab9e4fe 100644 --- a/opendaylight/md-sal/topology-manager/pom.xml +++ b/opendaylight/md-sal/topology-manager/pom.xml @@ -23,22 +23,18 @@ org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT org.opendaylight.controller sal-binding-util - 1.1-SNAPSHOT org.opendaylight.controller.model model-flow-service - 1.1-SNAPSHOT org.opendaylight.controller.model model-inventory - 1.1-SNAPSHOT org.opendaylight.controller.model 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 1d48e9287b..460aec6ac6 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,8 +8,6 @@ package org.opendaylight.controller.netconf.persist.impl; -import io.netty.channel.EventLoopGroup; - import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; @@ -30,7 +28,7 @@ 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.NetconfUtil; -import org.opendaylight.controller.netconf.util.messages.NetconfMessageAdditionalHeader; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -40,12 +38,12 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import io.netty.channel.EventLoopGroup; @Immutable public class ConfigPusher { - private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class); + 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; @@ -134,8 +132,8 @@ public class ConfigPusher { final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(maxWaitForCapabilitiesMillis); int attempt = 0; - String additionalHeader = NetconfMessageAdditionalHeader.toString("unknown", address.getAddress().getHostAddress(), - Integer.toString(address.getPort()), "tcp", Optional.of("persister")); + NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("unknown", address.getAddress().getHostAddress(), + Integer.toString(address.getPort()), "tcp", "persister"); Set latestCapabilities = null; while (System.nanoTime() < deadlineNanos) { diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java index afca33328e..78586a3fec 100644 --- a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java @@ -10,30 +10,18 @@ package org.opendaylight.controller.netconf.api; import org.w3c.dom.Document; -import com.google.common.base.Optional; - /** * NetconfMessage represents a wrapper around org.w3c.dom.Document. Needed for * implementing ProtocolMessage interface. */ -public final class NetconfMessage { - private final String additionalHeader; +public class NetconfMessage { private final Document doc; public NetconfMessage(final Document doc) { - this(doc, null); - } - - public NetconfMessage(Document doc, String additionalHeader) { this.doc = doc; - this.additionalHeader = additionalHeader; } public Document getDocument() { return this.doc; } - - public Optional getAdditionalHeader() { - return additionalHeader== null ? Optional.absent() : Optional.of(additionalHeader); - } } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java index bff2a54c58..43664b3233 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java @@ -18,6 +18,7 @@ import java.io.Closeable; import java.net.InetSocketAddress; import org.opendaylight.controller.netconf.util.AbstractChannelInitializer; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.protocol.framework.AbstractDispatcher; import org.opendaylight.protocol.framework.ReconnectStrategy; import org.opendaylight.protocol.framework.ReconnectStrategyFactory; @@ -31,19 +32,23 @@ public class NetconfClientDispatcher extends AbstractDispatcherabsent(), clientConnectionTimeoutMillis); + this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, + Optional. absent(), clientConnectionTimeoutMillis); } - public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, String additionalHeader, long connectionTimeoutMillis) { + public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, + NetconfHelloMessageAdditionalHeader additionalHeader, long connectionTimeoutMillis) { super(bossGroup, workerGroup); timer = new HashedWheelTimer(); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), connectionTimeoutMillis); + this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), + connectionTimeoutMillis); } public Future createClient(InetSocketAddress address, @@ -57,7 +62,7 @@ public class NetconfClientDispatcher extends AbstractDispatcher promise) { - new ClientChannelInitializer( negotatorFactory, sessionListener).initialize(ch, promise); + new ClientChannelInitializer(negotiatorFactory, sessionListener).initialize(ch, promise); } }); } @@ -65,7 +70,7 @@ public class NetconfClientDispatcher extends AbstractDispatcher createReconnectingClient(final InetSocketAddress address, final NetconfClientSessionListener listener, final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) { - final ClientChannelInitializer init = new ClientChannelInitializer(negotatorFactory, listener); + final ClientChannelInitializer init = new ClientChannelInitializer(negotiatorFactory, listener); return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy, new PipelineInitializer() { @@ -88,14 +93,20 @@ public class NetconfClientDispatcher extends AbstractDispatcher promise) { - ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator( - new SessionListenerFactory() { - @Override - public NetconfClientSessionListener getSessionListener() { - return sessionListener; - } - }, ch, promise)); + public void initialize(SocketChannel ch, Promise promise) { + super.initialize(ch,promise); + } + + @Override + protected void initializeSessionNegotiator(SocketChannel ch, Promise promise) { + ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, + negotiatorFactory.getSessionNegotiator( + new SessionListenerFactory() { + @Override + public NetconfClientSessionListener getSessionListener() { + return sessionListener; + } + }, ch, promise)); } } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java index 3c2e814d89..c742bafe5e 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java @@ -8,10 +8,6 @@ package org.opendaylight.controller.netconf.client; -import io.netty.channel.Channel; -import io.netty.util.Timer; -import io.netty.util.concurrent.Promise; - import java.util.Collection; import java.util.List; @@ -19,9 +15,9 @@ import javax.annotation.Nullable; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; -import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.api.NetconfSessionPreferences; import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage; import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; @@ -32,6 +28,10 @@ import org.w3c.dom.Node; import com.google.common.base.Function; import com.google.common.collect.Collections2; +import io.netty.channel.Channel; +import io.netty.util.Timer; +import io.netty.util.concurrent.Promise; + public class NetconfClientSessionNegotiator extends AbstractNetconfSessionNegotiator { @@ -71,7 +71,7 @@ public class NetconfClientSessionNegotiator extends } @Override - protected NetconfClientSession getSession(NetconfClientSessionListener sessionListener, Channel channel, NetconfMessage message) { + protected NetconfClientSession getSession(NetconfClientSessionListener sessionListener, Channel channel, NetconfHelloMessage message) { return new NetconfClientSession(sessionListener, channel, extractSessionId(message.getDocument()), getCapabilities(message.getDocument())); } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java index e678a601ff..bb372b3aff 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java @@ -17,6 +17,8 @@ import java.io.InputStream; import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.api.NetconfSessionPreferences; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.opendaylight.protocol.framework.SessionListenerFactory; import org.opendaylight.protocol.framework.SessionNegotiator; @@ -28,11 +30,11 @@ import com.google.common.base.Preconditions; public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory { - private final Optional additionalHeader; + private final Optional additionalHeader; private final long connectionTimeoutMillis; private final Timer timer; - public NetconfClientSessionNegotiatorFactory(Timer timer, Optional additionalHeader, long connectionTimeoutMillis) { + public NetconfClientSessionNegotiatorFactory(Timer timer, Optional additionalHeader, long connectionTimeoutMillis) { this.timer = Preconditions.checkNotNull(timer); this.additionalHeader = additionalHeader; this.connectionTimeoutMillis = connectionTimeoutMillis; @@ -53,9 +55,12 @@ public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorF Promise promise) { // Hello message needs to be recreated every time NetconfMessage helloMessage = loadHelloMessageTemplate(); + if(this.additionalHeader.isPresent()) { - helloMessage = new NetconfMessage(helloMessage.getDocument(), additionalHeader.get()); - } + helloMessage = new NetconfHelloMessage(helloMessage.getDocument(), additionalHeader.get()); + } else + helloMessage = new NetconfHelloMessage(helloMessage.getDocument()); + NetconfSessionPreferences proposal = new NetconfSessionPreferences(helloMessage); return new NetconfClientSessionNegotiator(proposal, promise, channel, timer, sessionListenerFactory.getSessionListener(), connectionTimeoutMillis); diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java index 0737279b04..5b82ff2215 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java @@ -21,6 +21,7 @@ import org.opendaylight.controller.netconf.util.AbstractChannelInitializer; import org.opendaylight.controller.netconf.util.handler.ssh.SshHandler; import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler; import org.opendaylight.controller.netconf.util.handler.ssh.client.Invoker; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.protocol.framework.ReconnectStrategy; import org.opendaylight.protocol.framework.ReconnectStrategyFactory; import org.opendaylight.protocol.framework.SessionListenerFactory; @@ -31,22 +32,24 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher { private final AuthenticationHandler authHandler; private final HashedWheelTimer timer; - private final NetconfClientSessionNegotiatorFactory negotatorFactory; + private final NetconfClientSessionNegotiatorFactory negotiatorFactory; public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup, EventLoopGroup workerGroup, long connectionTimeoutMillis) { super(bossGroup, workerGroup, connectionTimeoutMillis); this.authHandler = authHandler; this.timer = new HashedWheelTimer(); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.absent(), connectionTimeoutMillis); + this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, + Optional. absent(), connectionTimeoutMillis); } public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup, - EventLoopGroup workerGroup, String additionalHeader, long socketTimeoutMillis) { + EventLoopGroup workerGroup, NetconfHelloMessageAdditionalHeader additionalHeader, long socketTimeoutMillis) { super(bossGroup, workerGroup, additionalHeader, socketTimeoutMillis); this.authHandler = authHandler; this.timer = new HashedWheelTimer(); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), socketTimeoutMillis); + this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), + socketTimeoutMillis); } @Override @@ -56,7 +59,7 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher { @Override public void initializeChannel(SocketChannel arg0, Promise arg1) { - new NetconfSshClientInitializer(authHandler, negotatorFactory, sessionListener).initialize(arg0, arg1); + new NetconfSshClientInitializer(authHandler, negotiatorFactory, sessionListener).initialize(arg0, arg1); } }); @@ -66,7 +69,7 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher { public Future createReconnectingClient(final InetSocketAddress address, final NetconfClientSessionListener listener, final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) { - final NetconfSshClientInitializer init = new NetconfSshClientInitializer(authHandler, negotatorFactory, listener); + final NetconfSshClientInitializer init = new NetconfSshClientInitializer(authHandler, negotiatorFactory, listener); return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy, new PipelineInitializer() { @@ -103,14 +106,15 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher { } @Override - protected void initializeAfterDecoder(SocketChannel ch, Promise promise) { - ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() { + protected void initializeSessionNegotiator(SocketChannel ch, + Promise promise) { + ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, + negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() { @Override public NetconfClientSessionListener getSessionListener() { return sessionListener; } }, ch, promise)); - } } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java index bd39049c56..ee9009762e 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java @@ -41,6 +41,8 @@ public class NetconfServerDispatcher extends AbstractDispatcher { + public static final String DESERIALIZER_EX_HANDLER_KEY = "deserializerExHandler"; + private final NetconfServerSessionNegotiatorFactory negotiatorFactory; private final NetconfServerSessionListenerFactory listenerFactory; @@ -51,9 +53,14 @@ public class NetconfServerDispatcher extends AbstractDispatcher promise) { - ch.pipeline().addLast("deserializerExHandler", new DeserializerExceptionHandler()); - ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(listenerFactory, ch, promise)); + protected void initializeMessageDecoder(SocketChannel ch) { + super.initializeMessageDecoder(ch); + ch.pipeline().addLast(DESERIALIZER_EX_HANDLER_KEY, new DeserializerExceptionHandler()); + } + + @Override + protected void initializeSessionNegotiator(SocketChannel ch, Promise promise) { + ch.pipeline().addAfter(DESERIALIZER_EX_HANDLER_KEY, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, negotiatorFactory.getSessionNegotiator(listenerFactory, ch, promise)); } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java index 93d4e55410..9ddc64f1a1 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java @@ -17,6 +17,7 @@ import java.util.regex.Pattern; import org.opendaylight.controller.netconf.api.AbstractNetconfSession; import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.NetconfTcp; @@ -38,13 +39,13 @@ public final class NetconfServerSession extends AbstractNetconfSession { @@ -35,60 +35,21 @@ public class NetconfServerSessionNegotiator extends } @Override - protected NetconfServerSession getSession(NetconfServerSessionListener sessionListener, Channel channel, NetconfMessage message) { - Optional additionalHeader = message.getAdditionalHeader(); + protected NetconfServerSession getSession(NetconfServerSessionListener sessionListener, Channel channel, NetconfHelloMessage message) { + Optional additionalHeader = message.getAdditionalHeader(); - AdditionalHeader parsedHeader; + NetconfHelloMessageAdditionalHeader parsedHeader; if (additionalHeader.isPresent()) { - parsedHeader = AdditionalHeaderUtil.fromString(additionalHeader.get()); + parsedHeader = additionalHeader.get(); } else { - parsedHeader = new AdditionalHeader("unknown", ((InetSocketAddress)channel.localAddress()).getHostString(), + InetSocketAddress inetSocketAddress = (InetSocketAddress) channel.localAddress(); + parsedHeader = new NetconfHelloMessageAdditionalHeader("unknown", inetSocketAddress.getHostString(), Integer.toString(inetSocketAddress.getPort()), "tcp", "client"); } + logger.debug("Additional header from hello parsed as {} from {}", parsedHeader, additionalHeader); return new NetconfServerSession(sessionListener, channel, sessionPreferences.getSessionId(), parsedHeader); } - public static class AdditionalHeader { - - private final String username; - private final String address; - private final String transport; - private final String sessionIdentifier; - - public AdditionalHeader(String userName, String hostAddress, String transport, String sessionIdentifier) { - this.address = hostAddress; - this.username = userName; - this.transport = transport; - this.sessionIdentifier = sessionIdentifier; - } - - String getUsername() { - return username; - } - - String getAddress() { - return address; - } - - String getTransport() { - return transport; - } - - String getSessionType() { - return sessionIdentifier; - } - - @Override - public String toString() { - final StringBuffer sb = new StringBuffer("AdditionalHeader{"); - sb.append("username='").append(username).append('\''); - sb.append(", address='").append(address).append('\''); - sb.append(", transport='").append(transport).append('\''); - sb.append('}'); - return sb.toString(); - } - } - -} + } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java index 8086b748d7..e052f61cc9 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java @@ -8,20 +8,15 @@ package org.opendaylight.controller.netconf.impl; +import com.google.common.base.Preconditions; import io.netty.channel.Channel; import io.netty.util.Timer; import io.netty.util.concurrent.Promise; - -import java.io.InputStream; - -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; - -import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences; import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider; import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener; import org.opendaylight.controller.netconf.util.NetconfUtil; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage; import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -32,9 +27,11 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; -import com.google.common.base.Preconditions; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import java.io.InputStream; -public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory { +public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory { public static final String SERVER_HELLO_XML_LOCATION = "/server_hello.xml"; @@ -77,7 +74,7 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF private static final XPathExpression capabilitiesXPath = XMLNetconfUtil .compileXPath("/netconf:hello/netconf:capabilities"); - private NetconfMessage createHelloMessage(long sessionId) { + private NetconfHelloMessage createHelloMessage(long sessionId) { Document helloMessageTemplate = getHelloTemplateClone(); // change session ID @@ -96,7 +93,7 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF capabilityElement.setTextContent(capability); capabilitiesElement.appendChild(capabilityElement); } - return new NetconfMessage(helloMessageTemplate); + return new NetconfHelloMessage(helloMessageTemplate); } private synchronized Document getHelloTemplateClone() { diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java deleted file mode 100644 index 5c630dd343..0000000000 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.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.netconf.impl.util; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiator.AdditionalHeader; - -import com.google.common.base.Preconditions; - -public class AdditionalHeaderUtil { - - private static final Pattern pattern = Pattern - .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+)[^\\]]+\\]"); - private static final Pattern customHeaderPattern = Pattern - .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+);(?[a-z]+)[^\\]]+\\]"); - - public static AdditionalHeader fromString(String additionalHeader) { - additionalHeader = additionalHeader.trim(); - Matcher matcher = pattern.matcher(additionalHeader); - Matcher matcher2 = customHeaderPattern.matcher(additionalHeader); - Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s", - additionalHeader, pattern); - String username = matcher.group("username"); - String address = matcher.group("address"); - String transport = matcher.group("transport"); - String sessionIdentifier = "client"; - if (matcher2.matches()) { - sessionIdentifier = matcher2.group("sessionIdentifier"); - } - return new AdditionalHeader(username, address, transport, sessionIdentifier); - } - -} diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java index 97d9a98b57..c2dcd67921 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java @@ -10,15 +10,15 @@ package org.opendaylight.controller.netconf.impl; import junit.framework.Assert; import org.junit.Test; -import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; public class AdditionalHeaderParserTest { @Test public void testParsing() throws Exception { String s = "[netconf;10.12.0.102:48528;ssh;;;;;;]"; - NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s); - Assert.assertEquals("netconf", header.getUsername()); + NetconfHelloMessageAdditionalHeader header = NetconfHelloMessageAdditionalHeader.fromString(s); + Assert.assertEquals("netconf", header.getUserName()); Assert.assertEquals("10.12.0.102", header.getAddress()); Assert.assertEquals("ssh", header.getTransport()); } @@ -26,8 +26,8 @@ public class AdditionalHeaderParserTest { @Test public void testParsing2() throws Exception { String s = "[tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]"; - NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s); - Assert.assertEquals("tomas", header.getUsername()); + NetconfHelloMessageAdditionalHeader header = NetconfHelloMessageAdditionalHeader.fromString(s); + Assert.assertEquals("tomas", header.getUserName()); Assert.assertEquals("10.0.0.0", header.getAddress()); Assert.assertEquals("tcp", header.getTransport()); } @@ -35,6 +35,6 @@ public class AdditionalHeaderParserTest { @Test(expected = IllegalArgumentException.class) public void testParsingNoUsername() throws Exception { String s = "[10.12.0.102:48528;ssh;;;;;;]"; - AdditionalHeaderUtil.fromString(s); + NetconfHelloMessageAdditionalHeader.fromString(s); } } diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java index 0ef2c285e4..c0d52ad85e 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java @@ -37,6 +37,7 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperation; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.controller.netconf.util.test.XmlFileLoader; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.slf4j.Logger; @@ -100,7 +101,8 @@ public class ConcurrentClientsTest { } nettyGroup = new NioEventLoopGroup(); - netconfClientDispatcher = new NetconfClientDispatcher( nettyGroup, nettyGroup, 5000); + NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("uname", "10.10.10.1", "830", "tcp", "client"); + netconfClientDispatcher = new NetconfClientDispatcher( nettyGroup, nettyGroup, additionalHeader, 5000); NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl(); factoriesListener.onAddNetconfOperationServiceFactory(mockOpF()); diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/MonitoringConstants.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/MonitoringConstants.java index 3a9d3bacc2..200cd344a6 100644 --- a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/MonitoringConstants.java +++ b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/MonitoringConstants.java @@ -9,10 +9,14 @@ package org.opendaylight.controller.netconf.monitoring; public class MonitoringConstants { - public static final String NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"; public static final String MODULE_NAME = "ietf-netconf-monitoring"; public static final String MODULE_REVISION = "2010-10-04"; + public static final String NAMESPACE = "urn:ietf:params:xml:ns:yang:" + MODULE_NAME; + public static final String EXTENSION_NAMESPACE = NAMESPACE + "-extension"; + + public static final String EXTENSION_NAMESPACE_PREFIX = "ncme"; + public static final String URI = String.format("%s?module=%s&revision=%s", NAMESPACE, MODULE_NAME, MODULE_REVISION); public static final String NETCONF_MONITORING_XML_ROOT_ELEMENT = "netconf-state"; diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java index 55aee72fda..8685ef7220 100644 --- a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java +++ b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java @@ -10,6 +10,8 @@ package org.opendaylight.controller.netconf.monitoring.xml.model; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlTransient; +import com.google.common.base.Joiner; +import org.opendaylight.controller.netconf.monitoring.MonitoringConstants; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session; import org.opendaylight.yangtools.yang.common.QName; @@ -69,13 +71,18 @@ final class MonitoringSession { public String getTransport() { try { QName qName = (QName) managementSession.getTransport().getField("QNAME").get(null); - return qName.getLocalName(); + // Add extension prefix if transport type is from extension yang module + if (qName.getNamespace().toString().equals(MonitoringConstants.EXTENSION_NAMESPACE)) { + return Joiner.on(':').join(MonitoringConstants.EXTENSION_NAMESPACE_PREFIX, qName.getLocalName()); + } else { + return qName.getLocalName(); + } } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { throw new IllegalArgumentException("Unknown transport type " + managementSession.getTransport(), e); } } - @XmlElement(name= "session-identifier") + @XmlElement(name= "session-identifier", namespace = MonitoringConstants.EXTENSION_NAMESPACE) public String getSessionType() { return managementSession.getAugmentation(Session1.class).getSessionIdentifier(); } diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/package-info.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/package-info.java index 85da5975d1..a96c3a3836 100644 --- a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/package-info.java +++ b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/package-info.java @@ -7,14 +7,16 @@ */ @XmlSchema( elementFormDefault = XmlNsForm.QUALIFIED, -// xmlns = { -// @XmlNs(namespaceURI = MonitoringConstants.NAMESPACE, prefix = "") -// } + xmlns = { + @XmlNs(namespaceURI = MonitoringConstants.EXTENSION_NAMESPACE, prefix = MonitoringConstants.EXTENSION_NAMESPACE_PREFIX), + @XmlNs(namespaceURI = MonitoringConstants.NAMESPACE, prefix = "") + }, namespace = MonitoringConstants.NAMESPACE ) package org.opendaylight.controller.netconf.monitoring.xml.model; import org.opendaylight.controller.netconf.monitoring.MonitoringConstants; +import javax.xml.bind.annotation.XmlNs; import javax.xml.bind.annotation.XmlNsForm; import javax.xml.bind.annotation.XmlSchema; \ No newline at end of file diff --git a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java index d4462f85d9..02129574da 100644 --- a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java +++ b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java @@ -13,8 +13,10 @@ import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringServi import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.NetconfTcp; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Transport; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions; @@ -39,7 +41,7 @@ public class JaxBSerializerTest { @Override public Sessions getSessions() { - return new SessionsBuilder().setSession(Lists.newArrayList(getMockSession())).build(); + return new SessionsBuilder().setSession(Lists.newArrayList(getMockSession(NetconfTcp.class), getMockSession(NetconfSsh.class))).build(); } @Override @@ -51,7 +53,7 @@ public class JaxBSerializerTest { Element xml = new JaxBSerializer().toXml(model); } - private Session getMockSession() { + private Session getMockSession(Class transportType) { Session mocked = mock(Session.class); Session1 mockedSession1 = mock(Session1.class); doReturn("client").when(mockedSession1).getSessionIdentifier(); @@ -62,7 +64,7 @@ public class JaxBSerializerTest { doReturn(new ZeroBasedCounter32(0L)).when(mocked).getInRpcs(); doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutNotifications(); doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutRpcErrors(); - doReturn(NetconfSsh.class).when(mocked).getTransport(); + doReturn(transportType).when(mocked).getTransport(); doReturn("username").when(mocked).getUsername(); doReturn(mockedSession1).when(mocked).getAugmentation(Session1.class); return mocked; diff --git a/opendaylight/netconf/netconf-ssh/pom.xml b/opendaylight/netconf/netconf-ssh/pom.xml index 3b4125b386..efad2148e9 100644 --- a/opendaylight/netconf/netconf-ssh/pom.xml +++ b/opendaylight/netconf/netconf-ssh/pom.xml @@ -35,7 +35,6 @@ org.opendaylight.controller usermanager - 0.4.2-SNAPSHOT diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java index d904ad7f26..3d5318073d 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java @@ -30,14 +30,14 @@ public class AuthProvider implements AuthProviderInterface { public AuthProvider(IUserManager ium,InputStream privateKeyFileInputStream) throws Exception { - this.um = ium; - if (this.um == null){ + AuthProvider.um = ium; + if (AuthProvider.um == null){ throw new Exception("No usermanager service available."); } List roles = new ArrayList(1); roles.add(UserLevel.SYSTEMADMIN.toString()); - this.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles)); + AuthProvider.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles)); try { PEM = IOUtils.toString(privateKeyFileInputStream); @@ -48,10 +48,10 @@ public class AuthProvider implements AuthProviderInterface { } @Override public boolean authenticated(String username, String password) throws Exception { - if (this.um == null){ + if (AuthProvider.um == null){ throw new Exception("No usermanager service available."); } - AuthResultEnum authResult = this.um.authenticate(username,password); + AuthResultEnum authResult = AuthProvider.um.authenticate(username,password); if (authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC)){ return true; } @@ -69,12 +69,12 @@ public class AuthProvider implements AuthProviderInterface { @Override public void removeUserManagerService() { - this.um = null; + AuthProvider.um = null; } @Override public void addUserManagerService(IUserManager userManagerService) { - this.um = userManagerService; + AuthProvider.um = userManagerService; } diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/IOThread.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/IOThread.java index b9c9c174dc..c53a625ad0 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/IOThread.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/IOThread.java @@ -7,25 +7,27 @@ */ package org.opendaylight.controller.netconf.ssh.threads; -import ch.ethz.ssh2.ServerConnection; -import ch.ethz.ssh2.ServerSession; import java.io.InputStream; import java.io.OutputStream; + import javax.annotation.concurrent.ThreadSafe; + import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ch.ethz.ssh2.ServerConnection; +import ch.ethz.ssh2.ServerSession; + @ThreadSafe public class IOThread extends Thread { private static final Logger logger = LoggerFactory.getLogger(IOThread.class); - private InputStream inputStream; - private OutputStream outputStream; - private String id; - private ServerSession servSession; - private ServerConnection servconnection; + private final InputStream inputStream; + private final OutputStream outputStream; + private final ServerSession servSession; + private final ServerConnection servconnection; private String customHeader; @@ -37,6 +39,7 @@ public class IOThread extends Thread { super.setName(id); logger.trace("IOThread {} created", super.getName()); } + public IOThread (InputStream is, OutputStream os, String id,ServerSession ss, ServerConnection conn,String header){ this.inputStream = is; this.outputStream = os; @@ -53,7 +56,7 @@ public class IOThread extends Thread { try { if (this.customHeader!=null && !this.customHeader.equals("")){ this.outputStream.write(this.customHeader.getBytes()); - logger.trace("adding {} header", this.customHeader); + logger.trace("adding {} header", this.customHeader); } IOUtils.copy(this.inputStream, this.outputStream); } catch (Exception e) { diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java index d1b5213f6e..204bf1d131 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java @@ -8,6 +8,16 @@ package org.opendaylight.controller.netconf.ssh.threads; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; + +import javax.annotation.concurrent.ThreadSafe; + +import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import ch.ethz.ssh2.AuthenticationResult; import ch.ethz.ssh2.PtySettings; import ch.ethz.ssh2.ServerAuthenticationCallback; @@ -16,25 +26,15 @@ import ch.ethz.ssh2.ServerConnectionCallback; import ch.ethz.ssh2.ServerSession; import ch.ethz.ssh2.ServerSessionCallback; import ch.ethz.ssh2.SimpleServerSessionCallback; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @ThreadSafe -public class SocketThread implements Runnable, ServerAuthenticationCallback, ServerConnectionCallback -{ - - private Socket socket; - private static final String USER = "netconf"; - private static final String PASSWORD = "netconf"; - private InetSocketAddress clientAddress; +public class SocketThread implements Runnable, ServerAuthenticationCallback, ServerConnectionCallback { private static final Logger logger = LoggerFactory.getLogger(SocketThread.class); + + private final Socket socket; + private final InetSocketAddress clientAddress; private ServerConnection conn = null; - private long sessionId; + private final long sessionId; private String currentUser; private final String remoteAddressWithPort; private final AuthProvider authProvider; @@ -77,6 +77,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser logger.error("SocketThread error ",e); } } + @Override public ServerSessionCallback acceptSession(final ServerSession session) { SimpleServerSessionCallback cb = new SimpleServerSessionCallback() @@ -85,6 +86,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser public Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException { return new Runnable(){ + @Override public void run() { if (subsystem.equals("netconf")){ @@ -145,6 +147,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser { return new Runnable() { + @Override public void run() { //noop @@ -157,6 +160,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser { return new Runnable() { + @Override public void run() { //noop @@ -168,22 +172,26 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser return cb; } + @Override public String initAuthentication(ServerConnection sc) { logger.trace("Established connection with host {}",remoteAddressWithPort); return "Established connection with host "+remoteAddressWithPort+"\r\n"; } + @Override public String[] getRemainingAuthMethods(ServerConnection sc) { return new String[] { ServerAuthenticationCallback.METHOD_PASSWORD }; } + @Override public AuthenticationResult authenticateWithNone(ServerConnection sc, String username) { return AuthenticationResult.FAILURE; } + @Override public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password) { @@ -199,6 +207,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser return AuthenticationResult.FAILURE; } + @Override public AuthenticationResult authenticateWithPublicKey(ServerConnection sc, String username, String algorithm, byte[] publickey, byte[] signature) { diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/StubUserManager.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/StubUserManager.java index 4a3a650ecd..6628310c97 100644 --- a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/StubUserManager.java +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/StubUserManager.java @@ -30,8 +30,8 @@ public class StubUserManager implements IUserManager{ private static String password; public StubUserManager(String user, String password){ - this.user = user; - this.password = password; + StubUserManager.user = user; + StubUserManager.password = password; } @Override public List getUserRoles(String userName) { @@ -40,7 +40,7 @@ public class StubUserManager implements IUserManager{ @Override public AuthResultEnum authenticate(String username, String password) { - if (this.user.equals(username) && this.password.equals(password)){ + if (StubUserManager.user.equals(username) && StubUserManager.password.equals(password)){ return AuthResultEnum.AUTH_ACCEPT_LOC; } return AuthResultEnum.AUTH_REJECT_LOC; diff --git a/opendaylight/netconf/netconf-util/pom.xml b/opendaylight/netconf/netconf-util/pom.xml index 0e06ab372f..e5bab5633b 100644 --- a/opendaylight/netconf/netconf-util/pom.xml +++ b/opendaylight/netconf/netconf-util/pom.xml @@ -45,7 +45,6 @@ io.netty netty-handler - ${netconf.netty.version}