* 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;
* specified host
*/
public class ARPRequest extends ARPEvent {
+ private static final long serialVersionUID = 1L;
private final Subnet subnet;
private final HostNodeConnector host;
<artifactId>ietf-topology</artifactId>
<version>${ietf-topology.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-topology-l3-unicast-igp</artifactId>
+ <version>${ietf-topology.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>opendaylight-l2-types</artifactId>
<artifactId>concepts</artifactId>
<version>${yangtools.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-client-api</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-client-impl</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
<!--Netty-->
<dependency>
<artifactId>sal-binding-broker-impl</artifactId>
<version>${mdsal.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <version>${mdsal.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-compatibility</artifactId>
<artifactId>statistics-manager</artifactId>
<version>${mdsal.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-remote</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-restconf-broker</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-util</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>concepts</artifactId>
<artifactId>config-persister-impl</artifactId>
<version>${netconf.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ietf-netconf-monitoring</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ietf-netconf-monitoring-extension</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
<!-- threadpool -->
<dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>concepts</artifactId>
- <version>${yangtools.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-impl</artifactId>
- <version>${yangtools.version}</version>
</dependency>
</dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-directory-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-directory-xml-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-file-xml-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
@Test
public void testLookupRuntimeBeans() throws Exception {
Set<ObjectName> 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<ObjectName> lookupRuntimeBeans(ConfigRegistryClient client)
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,
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-config-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-config-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-config-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>threadpool-config-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>threadpool-config-impl</artifactId>
- <version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <version>${logback.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</plugins>
</pluginManagement>
</build>
-</project>
\ No newline at end of file
+</project>
*/
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.
* </p>
*/
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<String, AttributeIfc> yangToAttributes;
- private final String nullableDescription, packageName, javaNamePrefix,
- namespace;
-
private final Map<String, QName> providedServices;
private Collection<RuntimeBeanEntry> runtimeBeans;
- private final QName yangModuleQName;
-
- public ModuleMXBeanEntry(IdentitySchemaNode id,
- Map<String, AttributeIfc> yangToAttributes, String packageName,
- Map<String, QName> providedServices2, String javaNamePrefix,
- String namespace, Collection<RuntimeBeanEntry> runtimeBeans,
- QName yangModuleQName) {
- this.globallyUniqueName = id.getQName().getLocalName();
+
+ ModuleMXBeanEntry(ModuleMXBeanEntryInitial initials, Map<String, AttributeIfc> yangToAttributes,
+ Map<String, QName> providedServices2, Collection<RuntimeBeanEntry> 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() {
}
public String getStubModuleName() {
- return javaNamePrefix + MODULE_SUFFIX;
+ return initial.javaNamePrefix + MODULE_SUFFIX;
}
public String getAbstractModuleName() {
}
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;
}
/**
}
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;
}
/**
Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
SchemaContext schemaContext,
TypeProviderWrapper typeProviderWrapper, String packageName) {
- Map<String, QName> 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<String, IdentitySchemaNode> 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<String, ModuleMXBeanEntry> result = new HashMap<>();
- // each module name should have an augmentation defined
- Map<String, IdentitySchemaNode> unaugmentedModuleIdentities = new HashMap<>(
- moduleIdentities);
- for (AugmentationSchema augmentation : currentModule.getAugmentations()) {
- Set<DataSchemaNode> 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<String, QName> 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<String, AttributeIfc> yangToAttributes = null;
- // runtime-data
- Collection<RuntimeBeanEntry> 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<RuntimeBeanEntry> 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<String, ModuleMXBeanEntry> entry : result.entrySet()) {
- ModuleMXBeanEntry module = entry.getValue();
- if (module.getAttributes() == null) {
- module.setYangToAttributes(Collections
- .<String, AttributeIfc> emptyMap());
- } else if (module.getRuntimeBeans() == null) {
- module.setRuntimeBeans(Collections
- .<RuntimeBeanEntry> emptyList());
- }
- }
- // check attributes name uniqueness
- for (Entry<String, ModuleMXBeanEntry> 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<String, QName> uniqueGeneratedClassesNames,
- DataSchemaNode when, Collection<RuntimeBeanEntry> 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<String, QName> 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<String, QName> uniqueGeneratedClassNames, QName parentQName,
- Map<String, AttributeIfc> yangToAttributes) {
- for (Entry<String, AttributeIfc> 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<String, AttributeIfc> getAttributes() {
+ return yangToAttributes;
}
- private static void checkUniqueTOAttr(
- Map<String, QName> 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<String, AttributeIfc> newAttributes) {
+ this.yangToAttributes = newAttributes;
}
- private static Collection<RuntimeBeanEntry> 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<String, AttributeIfc> fillConfiguration(
- ChoiceCaseNode choiceCaseNode, Module currentModule,
- TypeProviderWrapper typeProviderWrapper,
- Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
- SchemaContext schemaContext, String packageName) {
- Map<String, AttributeIfc> 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<String, QName> findProvidedServices(
- IdentitySchemaNode moduleIdentity, Module currentModule,
- Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
- SchemaContext schemaContext) {
- Map<String, QName> 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<QName, ServiceInterfaceEntry> 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<? extends AbstractDependencyAttribute> 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<? extends AbstractDependencyAttribute> 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<? extends AbstractDependencyAttribute> extractDependency(
- DataNodeContainer dataNodeContainer, DataSchemaNode attrNode,
- Module currentModule,
- Map<QName, ServiceInterfaceEntry> 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<QName, ServiceInterfaceEntry> 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<String, AttributeIfc> getAttributes() {
- return yangToAttributes;
- }
-
- private void setYangToAttributes(Map<String, AttributeIfc> 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
- + '\'' + '}';
}
}
--- /dev/null
+/*
+ * 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<QName, ServiceInterfaceEntry> qNamesToSIEs;
+ private SchemaContext schemaContext;
+ private TypeProviderWrapper typeProviderWrapper;
+ private String packageName;
+
+ public ModuleMXBeanEntryBuilder setModule(Module module) {
+ this.currentModule = module;
+ return this;
+ }
+
+ public ModuleMXBeanEntryBuilder setqNamesToSIEs(Map<QName, ServiceInterfaceEntry> 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<String, ModuleMXBeanEntry> 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<String, IdentitySchemaNode> moduleIdentities = getIdentityMap();
+
+ Map<String, QName> uniqueGeneratedClassesNames = new HashMap<>();
+
+ // each currentModule name should have an augmentation defined
+ Map<String, IdentitySchemaNode> unaugmentedModuleIdentities = new HashMap<>(
+ moduleIdentities);
+
+ Map<String, ModuleMXBeanEntry> result = new HashMap<>();
+
+ for (AugmentationSchema augmentation : currentModule.getAugmentations()) {
+ Set<DataSchemaNode> 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<String, ModuleMXBeanEntry> result) {
+ for (Map.Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
+ ModuleMXBeanEntry module = entry.getValue();
+ if (module.getAttributes() == null) {
+ module.setYangToAttributes(Collections
+ .<String, AttributeIfc> emptyMap());
+ } else if (module.getRuntimeBeans() == null) {
+ module.setRuntimeBeans(Collections
+ .<RuntimeBeanEntry> emptyList());
+ }
+ }
+ }
+
+ private static void checkUnaugumentedIdentities(Map<String, IdentitySchemaNode> unaugmentedModuleIdentities) {
+ if (unaugmentedModuleIdentities.size() > 0) {
+ logger.warn("Augmentation not found for all currentModule identities: {}",
+ unaugmentedModuleIdentities.keySet());
+ }
+ }
+
+ private static void checkAttributeNamesUniqueness(Map<String, QName> uniqueGeneratedClassesNames, Map<String, ModuleMXBeanEntry> result) {
+ for (Map.Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
+ checkUniqueRuntimeBeanAttributesName(entry.getValue(),
+ uniqueGeneratedClassesNames);
+ }
+ }
+
+ private Map<String, IdentitySchemaNode> getIdentityMap() {
+ Map<String, IdentitySchemaNode> 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<ChoiceCaseNode> castChildNodesToChoiceCases(Set<DataSchemaNode> childNodes) {
+ return Collections2.transform(childNodes, new Function<DataSchemaNode, ChoiceCaseNode>() {
+ @Nullable
+ @Override
+ public ChoiceCaseNode apply(@Nullable DataSchemaNode input) {
+ return (ChoiceCaseNode) input;
+ }
+ });
+ }
+
+ private boolean areAllChildrenChoiceCaseNodes(Set<DataSchemaNode> childNodes) {
+ for (DataSchemaNode childNode : childNodes) {
+ if (childNode instanceof ChoiceCaseNode == false)
+ return false;
+ }
+ return true;
+ }
+
+ private void processChoiceCaseNode(Map<String, ModuleMXBeanEntry> result,
+ Map<String, QName> uniqueGeneratedClassesNames, String configModulePrefix,
+ Map<String, IdentitySchemaNode> moduleIdentities,
+ Map<String, IdentitySchemaNode> 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<String, QName> 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<String, AttributeIfc> yangToAttributes = null;
+ // runtime-data
+ Collection<RuntimeBeanEntry> 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<RuntimeBeanEntry> 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<String, QName> uniqueGeneratedClassesNames,
+ DataSchemaNode when, Collection<RuntimeBeanEntry> 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<String, QName> 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<String, QName> uniqueGeneratedClassNames,
+ QName parentQName, Map<String, AttributeIfc> yangToAttributes) {
+ for (Map.Entry<String, AttributeIfc> 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<String, QName> 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<RuntimeBeanEntry> 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<String, AttributeIfc> fillConfiguration(ChoiceCaseNode choiceCaseNode, Module currentModule,
+ TypeProviderWrapper typeProviderWrapper, Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
+ SchemaContext schemaContext, String packageName) {
+ Map<String, AttributeIfc> 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<String, QName> findProvidedServices(IdentitySchemaNode moduleIdentity, Module currentModule,
+ Map<QName, ServiceInterfaceEntry> qNamesToSIEs, SchemaContext schemaContext) {
+ Map<String, QName> 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<QName, ServiceInterfaceEntry> 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<? extends AbstractDependencyAttribute> 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<? extends AbstractDependencyAttribute> 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<? extends AbstractDependencyAttribute> extractDependency(DataNodeContainer dataNodeContainer,
+ DataSchemaNode attrNode, Module currentModule, Map<QName, ServiceInterfaceEntry> 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<QName, ServiceInterfaceEntry> 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);
+ }
+
+}
}
// convert RpcDefinition to Rpc
for (RpcDefinition rpcDefinition : rpcDefinitions) {
- String name = ModuleMXBeanEntry
+ String name = TypeProviderWrapper
.findJavaParameter(rpcDefinition);
AttributeIfc returnType;
if (rpcDefinition.getOutput() == null
"More than one key is not supported in " + listSchemaNode);
}
- String javaNamePrefix = ModuleMXBeanEntry
+ String javaNamePrefix = TypeProviderWrapper
.findJavaNamePrefix(listSchemaNode);
RuntimeBeanEntry rbFromAttributes = new RuntimeBeanEntry(packageName,
*/
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;
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);
*/
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 {
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
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;
.entrySet()) {
capitalizedPropertiesToTypesMap.put(
- ModuleMXBeanEntry.convertToJavaName(entry.getKey(), true),
+ TypeProviderWrapper.convertToJavaName(entry.getKey(), true),
entry.getValue());
}
return capitalizedPropertiesToTypesMap;
.entrySet()) {
jmxPropertiesToTypesMap.put(
- ModuleMXBeanEntry.convertToJavaName(entry.getKey(), false),
+ TypeProviderWrapper.convertToJavaName(entry.getKey(), false),
entry.getValue());
}
return jmxPropertiesToTypesMap;
, PACKAGE_NAME);
Map<String, AttributeIfc> attributes = namesToMBEs.get("impl-netconf")
.getAttributes();
+
+ assertCorrectAttributesSize(namesToMBEs, attributes);
+
//
DependencyAttribute threadFactoryAttribute = (DependencyAttribute) attributes
.get("thread-factory");
assertThat(threadFactoryAttribute.getType().getName(), is("ObjectName"));
}
+ private void assertCorrectAttributesSize(Map<String, ModuleMXBeanEntry> namesToMBEs, Map<String, AttributeIfc> 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<RuntimeBeanEntry> runtimeBeans, String yangName) {
for (RuntimeBeanEntry rb : runtimeBeans) {
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));
import ietf-inet-types { prefix inet; revision-date 2010-09-24;}
import config-threads { prefix th; revision-date 2013-04-09; }
-
-
description
"Testing 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'";
}
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
type uint32;
}
+ leaf created-sessions-2 {
+ type uint32;
+ }
+
}
}
+
}
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
- <version>${yangtools.version}</version>
<executions>
<execution>
<id>config</id>
* 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();
}
package org.opendaylight.controller.configuration.internal;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
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;
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 <ConfigurationEvent, String> configEvent;
private Set<IConfigurationAware> configurationAwareList = Collections
return saveConfigurationsInternal();
}
+
+ private List<String> getContainerDirectoryList() {
+ List<String> containerList = new ArrayList<String>();
+ 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<String> 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");
}
}
package org.opendaylight.controller.configuration.internal;
-import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Dictionary;
private static final Logger logger = LoggerFactory.getLogger(ContainerConfigurationService.class);
private IClusterContainerServices clusterServices;
private ConcurrentMap <ConfigurationEvent, String> 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<IConfigurationContainerAware> configurationAwareList = Collections
.synchronizedSet(new HashSet<IConfigurationContainerAware>());
- private String root;
private ObjectReader objReader;
private ObjectWriter objWriter;
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() {
* 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());
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.services</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>connectionmanager</artifactId>
- <version>0.1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.7.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal.connection</artifactId>
- <version>0.1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
package org.opendaylight.controller.containermanager.internal;
-import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
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
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<NodeConnector> ncList, UpdateType update, boolean notifyLocal) {
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-netconf-connector</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-broker-impl</artifactId>
- <version>${mdsal.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-remote</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-restconf-broker</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-spi</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-impl</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-config</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-compatibility</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-connector-api</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-rest-connector</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-base</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-statistics</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.md</groupId>
<artifactId>inventory-manager</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.md</groupId>
<artifactId>forwardingrules-manager</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.md</groupId>
<artifactId>topology-lldp-discovery</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.md</groupId>
<artifactId>topology-manager</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-topology</artifactId>
- <version>1.1-SNAPSHOT</version>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-topology</artifactId>
+ <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>ietf-topology</artifactId>
</dependency>
<dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-util</artifactId>
- <version>1.1-SNAPSHOT</version>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-util</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.md</groupId>
<artifactId>statistics-manager</artifactId>
- <version>${mdsal.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>concepts</artifactId>
- <version>${concepts.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>concepts</artifactId>
- <version>${yangtools.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-client-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-client-impl</artifactId>
</dependency>
<!-- config-->
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-manager</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-jmx-generator</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-store-api</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-store-impl</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>logback-config</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-api</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-file-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-file-xml-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-directory-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-directory-xml-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-directory-autodetect-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>shutdown-api</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>shutdown-impl</artifactId>
- <version>${config.version}</version>
</dependency>
<!-- Netconf -->
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-api</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-impl</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-util</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-client</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-mapping-api</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-ssh</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-netconf-connector</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-monitoring</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>ietf-netconf-monitoring</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>ietf-netconf-monitoring-extension</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-impl</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.servicemix.bundles</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>threadpool-config-api</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-config-api</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>threadpool-config-impl</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-threadgroup-config</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-event-executor-config</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-timer-config</artifactId>
- <version>${config.version}</version>
</dependency>
-
<!-- toaster example I'm pretty sure we should trim -->
<dependency>
<groupId>org.opendaylight.controller.samples</groupId>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-binding</artifactId>
- <version>${yangtools.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-model-util</artifactId>
- <version>${yangtools.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>configuration</artifactId>
- <version>0.4.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.services</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.7.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal.connection</artifactId>
- <version>0.1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>forwardingrulesmanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>connectionmanager</artifactId>
- <version>0.1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager</artifactId>
- <version>0.5.2-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>forwardingrulesmanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-compatibility</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>switchmanager</artifactId>
- <version>0.7.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>topologymanager</artifactId>
- <version>0.4.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>forwardingrulesmanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-compatibility</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.7.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-statistics</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.services</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
topology.dataService = session.getSALService(DataProviderService)
tpProvider.dataService = session.getSALService(DataProviderService)
+ inventory.start();
tpProvider.start();
}
private def Future<RpcResult<TransactionStatus>> 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);
private def Future<RpcResult<TransactionStatus>> 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();
}
private def toFutureStatus(Future<RpcResult<TransactionStatus>> future){
+ if(future == null){
+ return toStatus(true);
+ }
+
try {
val result = future.get();
return toStatus(result);
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
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;
@Property
List<IPluginOutInventoryService> inventoryPublisher = new CopyOnWriteArrayList<IPluginOutInventoryService>();
- def setInventoryPublisher(IPluginOutInventoryService listener){
+ private final InventoryNotificationProvider inventoryNotificationProvider = new InventoryNotificationProvider();
+
+ private final Map<InstanceIdentifier.PathArgument, List<InstanceIdentifier.PathArgument>> nodeToNodeConnectorsMap = new ConcurrentHashMap<InstanceIdentifier.PathArgument, List<InstanceIdentifier.PathArgument>>();
+
+ 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() {
override readAllFlow(Node node, boolean cached) {
val output = new ArrayList<FlowOnNode>();
- 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()
}
override readAllNodeConnector(Node node, boolean cached) {
-
- val ret = new ArrayList<NodeConnectorStatistics>();
- 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<NodeConnectorStatistics>();
+ 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());
}
override readAllNodeTable(Node node, boolean cached) {
- val ret = new ArrayList<NodeTableStatistics>();
-
- 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<NodeTableStatistics>();
+
+ 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);
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;
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);
}
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);
}
override onNodeConnectorRemoved(NodeConnectorRemoved update) {
- // NOOP
+ // Never received
}
override onNodeRemoved(NodeRemoved notification) {
val properties = Collections.<org.opendaylight.controller.sal.core.Property>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<? extends DataObject>) == null ){
+ if(!isKnownNodeConnector(update.nodeConnectorRef.value)){
updateType = UpdateType.ADDED;
+ recordNodeConnector(update.nodeConnectorRef.value);
}
var nodeConnector = update.nodeConnectorRef.toADNodeConnector
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() {
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
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<FlowOnNode>();
- 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<NodeTableStatistics>();
-
- 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<NodeConnectorStatistics>();
-
- 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<FlowOnNode>();
+ 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<NodeTableStatistics>();
+
+ 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<NodeConnectorStatistics>();
+
+ 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<org.opendaylight.controller.sal.core.Property> properties){
+ for( publisher : inventoryPublisher){
+ publisher.updateNode(node, updateType, properties);
+ }
+ }
+
+ private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
+ for( publisher : inventoryPublisher){
+ publisher.updateNodeConnector(nodeConnector, updateType, properties);
+ }
+ }
+
+ private def isKnownNodeConnector(InstanceIdentifier<? extends Object> 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<org.opendaylight.controller.sal.core.Property> 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<org.opendaylight.controller.sal.core.Property> properties){
- for( publisher : inventoryPublisher){
- publisher.updateNodeConnector(nodeConnector, updateType, properties);
- }
- }
+ if(nodeConnectors == null){
+ return false;
+ }
+ return nodeConnectors.contains(nodeConnectorPath);
+ }
+
+
+ private def recordNodeConnector(InstanceIdentifier<? extends Object> 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<InstanceIdentifier.PathArgument>();
+ nodeToNodeConnectorsMap.put(nodePath, nodeConnectors);
+ }
+
+ nodeConnectors.add(nodeConnectorPath);
+ } finally {
+ nodeToNodeConnectorsLock.unlock();
+ }
+ }
+
+ private def removeNodeConnectors(InstanceIdentifier<? extends Object> nodeIdentifier){
+ val nodePath = nodeIdentifier.path.get(1);
+
+ nodeToNodeConnectorsMap.remove(nodePath);
+ }
}
--- /dev/null
+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<DataChangeListener> nodeConnectorDataChangeListenerRegistration;
+
+ private NodeConnectorDataChangeListener nodeConnectorDataChangeListener;
+
+ private DataProviderService dataProviderService;
+
+ private List<IPluginOutInventoryService> 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<IPluginOutInventoryService> inventoryPublisher) {
+ this.inventoryPublisher = inventoryPublisher;
+ }
+}
--- /dev/null
+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<IPluginOutInventoryService> inventoryPublisher;
+
+ public List<IPluginOutInventoryService> getInventoryPublisher() {
+ return this.inventoryPublisher;
+ }
+
+ public void setInventoryPublisher(final List<IPluginOutInventoryService> inventoryPublisher) {
+ this.inventoryPublisher = inventoryPublisher;
+ }
+
+ @Override
+ public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ final Map<InstanceIdentifier<?>,DataObject> createdOperationalData = change.getCreatedOperationalData();
+ final Map<InstanceIdentifier<?>,DataObject> updatedOperationalData = change.getUpdatedOperationalData();
+
+ final Set<Map.Entry<InstanceIdentifier<?>,DataObject>> createdEntries = createdOperationalData.entrySet();
+ final Set<Map.Entry<InstanceIdentifier<?>,DataObject>> updatedEntries = new HashSet<>();
+
+ updatedEntries.addAll(updatedOperationalData.entrySet());
+ updatedEntries.removeAll(createdEntries);
+
+ for(final Map.Entry<InstanceIdentifier<?>,DataObject> entry : createdEntries){
+ publishNodeConnectorUpdate(entry, UpdateType.ADDED);
+ }
+
+ for(final Map.Entry<InstanceIdentifier<?>,DataObject> entry : updatedEntries){
+ publishNodeConnectorUpdate(entry, UpdateType.CHANGED);
+ }
+ }
+
+ private void publishNodeConnectorUpdate(final Map.Entry<InstanceIdentifier<?>,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<Property> _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<Property> properties) {
+ LOG.debug("Publishing NodeConnector " + updateType.toString() + " nodeConnector Id = " + nodeConnector.getNodeConnectorIdAsString());
+
+ List<IPluginOutInventoryService> _inventoryPublisher = getInventoryPublisher();
+ for (final IPluginOutInventoryService publisher : _inventoryPublisher) {
+ publisher.updateNodeConnector(nodeConnector, updateType, properties);
+ }
+ }
+}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.xtend</groupId>
class NodeChangeCommiter implements OpendaylightInventoryListener {
+ static val LOG = LoggerFactory.getLogger(NodeChangeCommiter);
+
@Property
val FlowCapableInventoryProvider manager;
// Check path
val it = manager.startChange()
+
+ LOG.debug("removing node connector : " + ref.value.toString());
+
removeOperationalData(ref.value as InstanceIdentifier<? extends DataObject>);
commit()
}
data.addAugmentation(FlowCapableNodeConnector, augment)
}
+ LOG.debug("updating node connector : " + ref.value.toString());
+
putOperationalData(ref.value as InstanceIdentifier<NodeConnector>, data.build());
commit()
}
val ref = node.nodeRef;
val it = manager.startChange()
+ LOG.debug("removing node : " + ref.value.toString());
+
removeOperationalData(ref.value as InstanceIdentifier<? extends DataObject>);
commit()
}
data.addAugmentation(FlowCapableNode, augment)
}
+ LOG.debug("updating node : " + ref.value.toString());
+
putOperationalData(ref.value as InstanceIdentifier<Node>, data.build())
commit()
}
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>opendaylight-l2-types</artifactId>
- <version>2013.08.27.3</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>opendaylight-l2-types</artifactId>
- <version>2013.08.27.3</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>sal-connector-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
</exclusion>
</exclusions>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-remote</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-util</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<!-- Supporting Libraries -->
<dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
- <version>${osgi.core.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
* 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 extends RpcService> T getRpcService(Class<T> module);
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.dom.*,-->
org.opendaylight.controller.sal.binding.osgi.*,
</Private-Package>
</instructions>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
- <version>${osgi.core.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-config</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>ietf-inet-types</artifactId>
- <version>2010.09.24.3</version>
</dependency>
<dependency>
- <groupId>org.opendaylight.yangtools.model</groupId>
- <artifactId>ietf-topology-l3-unicast-igp</artifactId>
- <version>2013.10.21.1</version>
- <scope>test</scope>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-topology-l3-unicast-igp</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-flow-base</artifactId>
- <version>1.1-SNAPSHOT</version>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-flow-base</artifactId>
</dependency>
<dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-flow-service</artifactId>
</dependency>
<dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-flow-statistics</artifactId>
- <version>1.1-SNAPSHOT</version>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-flow-statistics</artifactId>
</dependency>
</dependencies>
</project>
*/
package org.opendaylight.controller.config.yang.md.sal.binding.impl;\r
\r
-import java.util.concurrent.ExecutorService;\r
-\r
-import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;\r
-import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl;\r
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer;\r
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;\r
-import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedDataBrokerImpl;\r
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;\r
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;\r
-import org.osgi.framework.BundleContext;\r
-import org.osgi.framework.ServiceReference;\r
+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;
\r
/**\r
*\r
dataBindingBroker = createStandAloneBroker(listeningExecutor);\r
}\r
dataBindingBroker.registerRuntimeBean(getRootRuntimeBeanRegistratorWrapper());\r
-\r
+ dataBindingBroker.setNotificationExecutor(SingletonHolder.getDefaultChangeEventExecutor());\r
return dataBindingBroker;\r
}\r
private BindingIndependentMappingService resolveMappingServiceDependency() {\r
if(getMappingService() != null) {\r
return getMappingServiceDependency();\r
}\r
- \r
+\r
ServiceReference<BindingIndependentMappingService> potentialMappingService = bundleContext.getServiceReference(BindingIndependentMappingService.class);\r
if(potentialMappingService != null) {\r
return bundleContext.getService(potentialMappingService);\r
*/
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;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-
/**
*
*/
@Override
public java.lang.AutoCloseable createInstance() {
-
+
RuntimeGeneratedMappingServiceProxy potential = tryToReuseGlobalInstance();
if(potential != null) {
return potential;
BindingIndependentMappingService, //
Delegator<BindingIndependentMappingService>, //
AutoCloseable {
-
+
private BindingIndependentMappingService delegate;
private ServiceReference<BindingIndependentMappingService> reference;
private BundleContext bundleContext;
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<InstanceIdentifier, CompositeNode> toDataDom(
Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> entry) {
return delegate.toDataDom(entry);
}
- @Override
public InstanceIdentifier toDataDom(
org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> path) {
return delegate.toDataDom(path);
}
- @Override
public DataObject dataObjectFromDataDom(
org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> 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<QName> getRpcQNamesFor(Class<? extends RpcService> service) {
return delegate.getRpcQNamesFor(service);
}
- @Override
- public DataContainer dataObjectFromDataDom(Class<? extends DataContainer> inputClass, CompositeNode domInput) {
- return delegate.dataObjectFromDataDom(inputClass, domInput);
- }
-
@Override
public Optional<Class<? extends RpcService>> getRpcServiceClassFor(String namespace, String revision) {
- return delegate.getRpcServiceClassFor(namespace, revision);
+ return delegate.getRpcServiceClassFor(namespace,revision);
}
+ public DataContainer dataObjectFromDataDom(Class<? extends DataContainer> inputClass, CompositeNode domInput) {
+ return delegate.dataObjectFromDataDom(inputClass, domInput);
+ }
+
@Override
public void close() throws Exception {
if(delegate != null) {
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) {
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;
+ }
}
*/
package org.opendaylight.controller.sal.binding.impl;\r
\r
-import java.util.Set;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLong;
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;
\r
\r
public class DataBrokerImpl extends AbstractDataBroker<InstanceIdentifier<? extends DataObject>, DataObject, DataChangeListener> //\r
implements DataProviderService, AutoCloseable {\r
\r
+ private final static class ContainsWildcarded implements Predicate<InstanceIdentifier<? extends DataObject>> {
+
+ private final InstanceIdentifier<? extends DataObject> key;
+
+ public ContainsWildcarded(InstanceIdentifier<? extends DataObject> key) {
+ this.key = key;
+ }
+
+ @Override
+ public boolean apply(InstanceIdentifier<? extends DataObject> input) {
+ return key.containsWildcarded(input);
+ }
+ }
+
+ private final static class IsContainedWildcarded implements Predicate<InstanceIdentifier<? extends DataObject>> {
+
+ private final InstanceIdentifier<? extends DataObject> key;
+
+ public IsContainedWildcarded(InstanceIdentifier<? extends DataObject> key) {
+ this.key = key;
+ }
+
+ @Override
+ public boolean apply(InstanceIdentifier<? extends DataObject> input) {
+ return input.containsWildcarded(key);
+ }
+ }
+
private final AtomicLong nextTransaction = new AtomicLong();\r
private final AtomicLong createdTransactionsCount = new AtomicLong();\r
\r
}
@Override
- protected boolean isAffectedBy(InstanceIdentifier<? extends DataObject> key,
- Set<InstanceIdentifier<? extends DataObject>> paths) {
- if (paths.contains(key)) {
- return true;
- }
- for (InstanceIdentifier<?> path : paths) {
- if (key.containsWildcarded(path)) {
- return true;
+ protected Predicate<InstanceIdentifier<? extends DataObject>> createContainsPredicate(final
+ InstanceIdentifier<? extends DataObject> key) {
+ return new ContainsWildcarded(key);
+ }
+
+ @Override
+ protected Predicate<InstanceIdentifier<? extends DataObject>> createIsContainedPredicate(final
+ InstanceIdentifier<? extends DataObject> key) {
+ return new IsContainedWildcarded(key);
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ protected Map<InstanceIdentifier<? extends DataObject>, DataObject> deepGetBySubpath(
+ Map<InstanceIdentifier<? extends DataObject>, DataObject> dataSet,
+ InstanceIdentifier<? extends DataObject> path) {
+ Builder<InstanceIdentifier<? extends DataObject>, DataObject> builder = ImmutableMap.builder();
+ Map<InstanceIdentifier<? extends DataObject>, DataObject> potential = Maps.filterKeys(dataSet, createIsContainedPredicate(path));
+ for(Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : potential.entrySet()) {
+ try {
+ builder.putAll(DataObjectReadingUtil.readData(entry.getValue(),(InstanceIdentifier)entry.getKey(),path));
+ } catch (Exception e) {
+ // FIXME : Log exception;
}
}
- return false;
- }\r
+ return builder.build();
+
+ }
+\r
}
import org.slf4j.LoggerFactory\r
import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder\rimport com.google.common.collect.Multimaps\r
import org.opendaylight.yangtools.concepts.util.ListenerRegistry\r
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener\rimport java.util.Set
-import com.google.common.collect.ImmutableSet
-import java.util.concurrent.Future
-
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener\rimport java.util.Set\r
+import java.util.Set\r
+import com.google.common.collect.ImmutableSet\r
+import java.util.concurrent.Future\r
+\r
class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable {\r
\r
val ListenerRegistry<NotificationInterestListener> interestListeners = ListenerRegistry.create;\r
submitAll(executor,tasks);\r
}\r
\r
- def submitAll(ExecutorService service, Set<NotifyTask> tasks) {
+ def submitAll(ExecutorService service, Set<NotifyTask> tasks) {\r
val ret = ImmutableSet.<Future<Object>>builder();\r
for(task : tasks) {\r
ret.add(service.submit(task));\r
}\r
- return ret.build();
+ return ret.build();\r
}\r
-\r
+ \r
override <T extends Notification> registerNotificationListener(Class<T> notificationType,\r
NotificationListener<T> listener) {\r
val reg = new GenericNotificationRegistration<T>(notificationType, listener, this);\r
*/
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;
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, //
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;
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;
private DataProviderService baDataService;
- private ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions = new ConcurrentHashMap<>();
- private ConcurrentMap<Object, DomToBindingTransaction> bindingOpenedTransactions = new ConcurrentHashMap<>();
+ private final ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions = new ConcurrentHashMap<>();
+ private final ConcurrentMap<Object, DomToBindingTransaction> 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<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> baCommitHandlerRegistration;
// private ListenerRegistration<BindingToDomRpcForwardingManager>
// bindingToDomRpcManager;
- private Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
+ private final Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
@Override
public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier<?> input) {
private RpcProviderRegistryImpl baRpcRegistryImpl;
- private org.opendaylight.controller.sal.dom.broker.spi.RpcRouter biRouter;
-
private NotificationProviderService baNotifyService;
private NotificationPublishService domNotificationService;
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;
}
}
private class BindingToDomTransaction implements
DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
- private DataModificationTransaction backing;
- private DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
+ private final DataModificationTransaction backing;
+ private final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
public BindingToDomTransaction(DataModificationTransaction backing,
DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
// FIXME: do registration based on only active commit handlers.
}
+ @Override
public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> requestCommit(
DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> domTransaction) {
Object identifier = domTransaction.getIdentifier();
private final Set<QName> supportedRpcs;
private final WeakReference<Class<? extends RpcService>> rpcServiceType;
- private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
- private Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
- private WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
+ private final Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
+ private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
+ private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
public DomToBindingRpcForwarder(Class<? extends RpcService> service) {
this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
private class DefaultInvocationStrategy extends RpcInvocationStrategy {
@SuppressWarnings("rawtypes")
- private WeakReference<Class> inputClass;
+ private final WeakReference<Class> inputClass;
@SuppressWarnings("rawtypes")
- private WeakReference<Class> outputClass;
+ private final WeakReference<Class> outputClass;
@SuppressWarnings({ "rawtypes", "unchecked" })
public DefaultInvocationStrategy(QName rpc, Method targetMethod, Class<?> outputClass,
@Override
public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
- if(biRouter != null) {
+ if(biRpcRegistry != null) {
CompositeNode xml = mappingService.toDataDom(input);
CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
- RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
+ RpcResult<CompositeNode> result = biRpcRegistry.invokeRpc(rpc, wrappedXml);
Object baResultValue = null;
if (result.getResult() != null) {
baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult());
super(rpc, targetMethod);
}
+ @Override
public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
@SuppressWarnings("unchecked")
Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
return Futures.immediateFuture(null);
}
}
-
+
private class NoOutputInvocationStrategy extends RpcInvocationStrategy {
-
+
@SuppressWarnings("rawtypes")
- private WeakReference<Class> inputClass;
+ private final WeakReference<Class> inputClass;
@SuppressWarnings({ "rawtypes", "unchecked" })
- public NoOutputInvocationStrategy(QName rpc, Method targetMethod,
+ public NoOutputInvocationStrategy(QName rpc, Method targetMethod,
Class<? extends DataContainer> inputClass) {
super(rpc,targetMethod);
this.inputClass = new WeakReference(inputClass);
}
-
-
+
+
@Override
public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
@Override
public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
- if(biRouter != null) {
+ if(biRpcRegistry != null) {
CompositeNode xml = mappingService.toDataDom(input);
CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
- RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
+ RpcResult<CompositeNode> result = biRpcRegistry.invokeRpc(rpc, wrappedXml);
Object baResultValue = null;
RpcResult<?> baResult = Rpcs.<Void>getRpcResult(result.isSuccessful(), null, result.getErrors());
return Futures.<RpcResult<?>>immediateFuture(baResult);
public void setDomNotificationService(NotificationPublishService domService) {
this.domNotificationService = domService;
}
-
+
private class DomToBindingNotificationForwarder implements NotificationInterestListener, NotificationListener {
- private ConcurrentMap<QName, WeakReference<Class<? extends Notification>>> notifications = new ConcurrentHashMap<>();
- private Set<QName> supportedNotifications = new HashSet<>();
-
+ private final ConcurrentMap<QName, WeakReference<Class<? extends Notification>>> notifications = new ConcurrentHashMap<>();
+ private final Set<QName> supportedNotifications = new HashSet<>();
+
@Override
public Set<QName> getSupportedNotifications() {
return Collections.unmodifiableSet(supportedNotifications);
if (potentialClass != null) {
final DataContainer baNotification = mappingService.dataObjectFromDataDom(potentialClass,
notification);
-
+
if (baNotification instanceof Notification) {
baNotifyService.publish((Notification) baNotification);
}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-native</artifactId>
<scope>test</scope>
- <version>${exam.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
* 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;
private static final InstanceIdentifier<Nodes> NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
.toInstance();
-
private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier//
.builder(NODES_INSTANCE_ID_BA) //
.child(Node.class, NODE_KEY).toInstance();
-
private static final InstanceIdentifier<SupportedActions> 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<FlowCapableNode> 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<InstanceIdentifier<?>, 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<FlowCapableNode> FLOW_AUGMENTATION_PATH = InstanceIdentifier //
+ .builder(NODE_INSTANCE_ID_BA) //
+ .augmentation(FlowCapableNode.class) //
+ .build();
+ private DataChangeEvent<InstanceIdentifier<?>, DataObject> lastReceivedChangeEvent;
/**
* Test for Bug 148
@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));
baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build());
RpcResult<TransactionStatus> 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());
fnub.setDescription("Description Foo");
fnub.setSoftware("JUnit emulated");
FlowCapableNode fnu = fnub.build();
- InstanceIdentifier<FlowCapableNode> augmentIdentifier = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance();
+ InstanceIdentifier<FlowCapableNode> 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);
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);
DataModificationTransaction baseTransaction = baDataService.beginTransaction();
baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build());
RpcResult<TransactionStatus> 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<NodeConnector> ncPath = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA)
- .child(NodeConnector.class, ncKey).toInstance();
+ .child(NodeConnector.class, ncKey).toInstance();
InstanceIdentifier<FlowCapableNodeConnector> ncAugmentPath = InstanceIdentifier.builder(ncPath)
- .augmentation(FlowCapableNodeConnector.class).toInstance();
+ .augmentation(FlowCapableNodeConnector.class).toInstance();
NodeConnectorBuilder nc = new NodeConnectorBuilder();
nc.setKey(ncKey);
RpcResult<TransactionStatus> 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());
}
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());
}
- 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);
}
@Override
public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
- receivedChangeEvent = change;
+ lastReceivedChangeEvent = change;
}
}
<!-- Sonar jacoco plugin to get integration test coverage info -->
<sonar.jacoco.reportPath>../sal-binding-broker/target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.jacoco.itReportPath>../sal-binding-broker/target/jacoco-it.exec</sonar.jacoco.itReportPath>
- <netconf.version>0.2.4-SNAPSHOT</netconf.version>
- <config.version>0.2.4-SNAPSHOT</config.version>
- <moxy.controller.version>2.5.0</moxy.controller.version>
</properties>
<build>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-native</artifactId>
- <version>${exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId>
- <version>${exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-netconf-connector</artifactId>
- <version>${netconf.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-store-impl</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>logback-config</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-impl</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-file-xml-adapter</artifactId>
- <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
- <version>${moxy.controller.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.core</artifactId>
- <version>${moxy.controller.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-impl</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-monitoring</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-client</artifactId>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-link-mvn</artifactId>
- <version>${exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
<artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
- <version>1.7.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
- <version>1.0.9</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <version>1.0.9</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-manager</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
- <version>5.0.0</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
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,
}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
private final Map<C, Set<P>> removal;
private final Map<C, Set<P>> announcement;
- public RouteChangeImpl(ImmutableMap<C, Set<P>> removal, ImmutableMap<C, Set<P>> announcement) {
+ public RouteChangeImpl(ImmutableMap<C, Set<P>> announcement, ImmutableMap<C, Set<P>> removal) {
super();
this.removal = removal;
this.announcement = announcement;
--- /dev/null
+/**
+ * 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<P extends Path<P>, D extends Object, DCL extends DataChangeListener<P, D>>
+ implements DataModificationTransactionFactory<P, D>, DataReader<P, D>, DataChangePublisher<P, D, DCL>,
+ DataProvisionService<P, D> {
+ 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<P, D> dataReadRouter;
+
+ private final AtomicLong submittedTransactionsCount = new AtomicLong();
+
+ private final AtomicLong failedTransactionsCount = new AtomicLong();
+
+ private final AtomicLong finishedTransactionsCount = new AtomicLong();
+
+ public AbstractDataReadRouter<P, D> getDataReadRouter() {
+ return this.dataReadRouter;
+ }
+
+ public void setDataReadRouter(final AbstractDataReadRouter<P, D> 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<P, DataChangeListenerRegistration<P, D, DCL>> listeners = Multimaps
+ .synchronizedSetMultimap(HashMultimap.<P, DataChangeListenerRegistration<P, D, DCL>> create());
+
+ private final Multimap<P, DataCommitHandlerRegistrationImpl<P, D>> commitHandlers = Multimaps
+ .synchronizedSetMultimap(HashMultimap.<P, DataCommitHandlerRegistrationImpl<P, D>> create());
+
+ private final Lock registrationLock = new ReentrantLock();
+
+ private final ListenerRegistry<RegistrationListener<DataCommitHandlerRegistration<P, D>>> commitHandlerRegistrationListeners = new ListenerRegistry<RegistrationListener<DataCommitHandlerRegistration<P, D>>>();
+
+ public AbstractDataBroker() {
+ }
+
+ protected ImmutableList<DataCommitHandler<P, D>> affectedCommitHandlers(final Set<P> paths) {
+ final Callable<ImmutableList<DataCommitHandler<P, D>>> _function = new Callable<ImmutableList<DataCommitHandler<P, D>>>() {
+ @Override
+ public ImmutableList<DataCommitHandler<P, D>> call() throws Exception {
+ Map<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>> _asMap = commitHandlers.asMap();
+ Set<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _entrySet = _asMap.entrySet();
+ FluentIterable<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _from = FluentIterable
+ .<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> from(_entrySet);
+ final Predicate<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _function = new Predicate<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>>() {
+ @Override
+ public boolean apply(final Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>> it) {
+ P _key = it.getKey();
+ boolean _isAffectedBy = isAffectedBy(_key, paths);
+ return _isAffectedBy;
+ }
+ };
+ FluentIterable<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _filter = _from
+ .filter(_function);
+ final Function<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>, Collection<DataCommitHandlerRegistrationImpl<P, D>>> _function_1 = new Function<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>, Collection<DataCommitHandlerRegistrationImpl<P, D>>>() {
+ @Override
+ public Collection<DataCommitHandlerRegistrationImpl<P, D>> apply(
+ final Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>> it) {
+ Collection<DataCommitHandlerRegistrationImpl<P, D>> _value = it.getValue();
+ return _value;
+ }
+ };
+ FluentIterable<DataCommitHandlerRegistrationImpl<P, D>> _transformAndConcat = _filter
+ .<DataCommitHandlerRegistrationImpl<P, D>> transformAndConcat(_function_1);
+ final Function<DataCommitHandlerRegistrationImpl<P, D>, DataCommitHandler<P, D>> _function_2 = new Function<DataCommitHandlerRegistrationImpl<P, D>, DataCommitHandler<P, D>>() {
+ @Override
+ public DataCommitHandler<P, D> apply(final DataCommitHandlerRegistrationImpl<P, D> it) {
+ DataCommitHandler<P, D> _instance = it.getInstance();
+ return _instance;
+ }
+ };
+ FluentIterable<DataCommitHandler<P, D>> _transform = _transformAndConcat
+ .<DataCommitHandler<P, D>> transform(_function_2);
+ return _transform.toList();
+ }
+ };
+ return AbstractDataBroker.<ImmutableList<DataCommitHandler<P, D>>> withLock(this.registrationLock, _function);
+ }
+
+ protected ImmutableList<DataCommitHandler<P, D>> probablyAffectedCommitHandlers(final HashSet<P> paths) {
+ final Callable<ImmutableList<DataCommitHandler<P, D>>> _function = new Callable<ImmutableList<DataCommitHandler<P, D>>>() {
+ @Override
+ public ImmutableList<DataCommitHandler<P, D>> call() throws Exception {
+ Map<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>> _asMap = commitHandlers.asMap();
+ Set<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _entrySet = _asMap.entrySet();
+ FluentIterable<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _from = FluentIterable
+ .<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> from(_entrySet);
+ final Predicate<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _function = new Predicate<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>>() {
+ @Override
+ public boolean apply(final Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>> it) {
+ P _key = it.getKey();
+ boolean _isProbablyAffectedBy = isProbablyAffectedBy(_key, paths);
+ return _isProbablyAffectedBy;
+ }
+ };
+ FluentIterable<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _filter = _from
+ .filter(_function);
+ final Function<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>, Collection<DataCommitHandlerRegistrationImpl<P, D>>> _function_1 = new Function<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>, Collection<DataCommitHandlerRegistrationImpl<P, D>>>() {
+ @Override
+ public Collection<DataCommitHandlerRegistrationImpl<P, D>> apply(
+ final Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>> it) {
+ Collection<DataCommitHandlerRegistrationImpl<P, D>> _value = it.getValue();
+ return _value;
+ }
+ };
+ FluentIterable<DataCommitHandlerRegistrationImpl<P, D>> _transformAndConcat = _filter
+ .<DataCommitHandlerRegistrationImpl<P, D>> transformAndConcat(_function_1);
+ final Function<DataCommitHandlerRegistrationImpl<P, D>, DataCommitHandler<P, D>> _function_2 = new Function<DataCommitHandlerRegistrationImpl<P, D>, DataCommitHandler<P, D>>() {
+ @Override
+ public DataCommitHandler<P, D> apply(final DataCommitHandlerRegistrationImpl<P, D> it) {
+ DataCommitHandler<P, D> _instance = it.getInstance();
+ return _instance;
+ }
+ };
+ FluentIterable<DataCommitHandler<P, D>> _transform = _transformAndConcat
+ .<DataCommitHandler<P, D>> transform(_function_2);
+ return _transform.toList();
+ }
+ };
+ return AbstractDataBroker.<ImmutableList<DataCommitHandler<P, D>>> withLock(this.registrationLock, _function);
+ }
+
+ protected Map<P, D> deepGetBySubpath(final Map<P, D> dataSet, final P path) {
+ return Collections.<P, D> emptyMap();
+ }
+
+ @Override
+ public final D readConfigurationData(final P path) {
+ AbstractDataReadRouter<P, D> _dataReadRouter = this.getDataReadRouter();
+ return _dataReadRouter.readConfigurationData(path);
+ }
+
+ @Override
+ public final D readOperationalData(final P path) {
+ AbstractDataReadRouter<P, D> _dataReadRouter = this.getDataReadRouter();
+ return _dataReadRouter.readOperationalData(path);
+ }
+
+ private static <T extends Object> T withLock(final Lock lock, final Callable<T> method) {
+ lock.lock();
+ try {
+ return method.call();
+ } catch (Exception e) {
+ throw Exceptions.sneakyThrow(e);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public final Registration<DataCommitHandler<P, D>> registerCommitHandler(final P path,
+ final DataCommitHandler<P, D> commitHandler) {
+ synchronized (commitHandler) {
+ final DataCommitHandlerRegistrationImpl<P, D> registration = new DataCommitHandlerRegistrationImpl<P, D>(
+ path, commitHandler, this);
+ commitHandlers.put(path, registration);
+ LOG.trace("Registering Commit Handler {} for path: {}", commitHandler, path);
+ for (final ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<P, D>>> 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<DCL> registerDataChangeListener(final P path, final DCL listener) {
+ synchronized (listeners) {
+ final DataChangeListenerRegistration<P, D, DCL> reg = new DataChangeListenerRegistration<P, D, DCL>(path,
+ listener, AbstractDataBroker.this);
+ listeners.put(path, reg);
+ final D initialConfig = getDataReadRouter().readConfigurationData(path);
+ final D initialOperational = getDataReadRouter().readOperationalData(path);
+ final DataChangeEvent<P, D> event = createInitialListenerEvent(path, initialConfig, initialOperational);
+ listener.onDataChanged(event);
+ return reg;
+ }
+ }
+
+ public final CompositeObjectRegistration<DataReader<P, D>> registerDataReader(final P path,
+ final DataReader<P, D> reader) {
+
+ final Registration<DataReader<P, D>> confReg = getDataReadRouter().registerConfigurationReader(path, reader);
+ final Registration<DataReader<P, D>> dataReg = getDataReadRouter().registerOperationalReader(path, reader);
+ return new CompositeObjectRegistration<DataReader<P, D>>(reader, Arrays.asList(confReg, dataReg));
+ }
+
+ @Override
+ public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<P, D>>> registerCommitHandlerListener(
+ final RegistrationListener<DataCommitHandlerRegistration<P, D>> commitHandlerListener) {
+ final ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<P, D>>> ret = this.commitHandlerRegistrationListeners
+ .register(commitHandlerListener);
+ return ret;
+ }
+
+ protected DataChangeEvent<P, D> createInitialListenerEvent(final P path, final D initialConfig,
+ final D initialOperational) {
+ InitialDataChangeEventImpl<P, D> _initialDataChangeEventImpl = new InitialDataChangeEventImpl<P, D>(
+ initialConfig, initialOperational);
+ return _initialDataChangeEventImpl;
+ }
+
+ protected final void removeListener(final DataChangeListenerRegistration<P, D, DCL> registration) {
+ synchronized (listeners) {
+ listeners.remove(registration.getPath(), registration);
+ }
+ }
+
+ protected final void removeCommitHandler(final DataCommitHandlerRegistrationImpl<P, D> registration) {
+ synchronized (commitHandlers) {
+
+ commitHandlers.remove(registration.getPath(), registration);
+ LOG.trace("Removing Commit Handler {} for path: {}", registration.getInstance(), registration.getPath());
+ for (final ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<P, D>>> 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<Entry<P, DataCommitHandlerRegistrationImpl<P, D>>> getActiveCommitHandlers() {
+ return commitHandlers.entries();
+ }
+
+ protected ImmutableList<ListenerStateCapture<P, D, DCL>> affectedListeners(final Set<P> paths) {
+
+ synchronized (listeners) {
+ return FluentIterable //
+ .from(listeners.asMap().entrySet()) //
+ .filter(new Predicate<Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>>>() {
+ @Override
+ public boolean apply(final Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>> it) {
+ return isAffectedBy(it.getKey(), paths);
+ }
+ }) //
+ .transform(
+ new Function<Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>>, ListenerStateCapture<P, D, DCL>>() {
+ @Override
+ public ListenerStateCapture<P, D, DCL> apply(
+ final Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>> it) {
+ return new ListenerStateCapture<P, D, DCL>(it.getKey(), it.getValue(),
+ createContainsPredicate(it.getKey()));
+ }
+ }) //
+ .toList();
+ }
+ }
+
+ protected ImmutableList<ListenerStateCapture<P, D, DCL>> probablyAffectedListeners(final Set<P> paths) {
+ synchronized (listeners) {
+ return FluentIterable //
+ .from(listeners.asMap().entrySet()) //
+ .filter(new Predicate<Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>>>() {
+ @Override
+ public boolean apply(final Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>> it) {
+ return isProbablyAffectedBy(it.getKey(), paths);
+ }
+ }) //
+ .transform(
+ new Function<Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>>, ListenerStateCapture<P, D, DCL>>() {
+ @Override
+ public ListenerStateCapture<P, D, DCL> apply(
+ final Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>> it) {
+ return new ListenerStateCapture<P, D, DCL>(it.getKey(), it.getValue(),
+ createIsContainedPredicate(it.getKey()));
+ }
+ }) //
+ .toList();
+ }
+ }
+
+ protected Predicate<P> createContainsPredicate(final P key) {
+ return new Predicate<P>() {
+ @Override
+ public boolean apply(final P other) {
+ return key.contains(other);
+ }
+ };
+ }
+
+ protected Predicate<P> createIsContainedPredicate(final P key) {
+ return new Predicate<P>() {
+ @Override
+ public boolean apply(final P other) {
+ return other.contains(key);
+ }
+ };
+ }
+
+ protected boolean isAffectedBy(final P key, final Set<P> paths) {
+ final Predicate<P> 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<P> paths) {
+ final Predicate<P> isContained = this.createIsContainedPredicate(key);
+ for (final P path : paths) {
+ if (isContained.apply(path)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ final Future<RpcResult<TransactionStatus>> commit(final AbstractDataTransaction<P, D> transaction) {
+ Preconditions.checkNotNull(transaction);
+ transaction.changeStatus(TransactionStatus.SUBMITED);
+ final TwoPhaseCommit<P, D, DCL> task = new TwoPhaseCommit<P, D, DCL>(transaction, this);
+ ;
+ this.getSubmittedTransactionsCount().getAndIncrement();
+ return this.getExecutor().submit(task);
+ }
+
+ private static class DataCommitHandlerRegistrationImpl<P extends Path<P>, D extends Object> //
+ extends AbstractObjectRegistration<DataCommitHandler<P, D>> //
+ implements DataCommitHandlerRegistration<P, D> {
+
+ private AbstractDataBroker<P, D, ? extends Object> dataBroker;
+ private final P path;
+
+ @Override
+ public P getPath() {
+ return this.path;
+ }
+
+ public DataCommitHandlerRegistrationImpl(final P path, final DataCommitHandler<P, D> instance,
+ final AbstractDataBroker<P, D, ? extends Object> broker) {
+ super(instance);
+ this.dataBroker = broker;
+ this.path = path;
+ }
+
+ @Override
+ protected void removeRegistration() {
+ this.dataBroker.removeCommitHandler(this);
+ this.dataBroker = null;
+ }
+ }
+}
+++ /dev/null
-/*
- * 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\r
-\r
-import com.google.common.collect.FluentIterable\r
-import com.google.common.collect.HashMultimap\r
-import com.google.common.collect.ImmutableList\r
-import com.google.common.collect.Multimap\r
-import java.util.ArrayList\r
-import java.util.Arrays\r
-import java.util.Collection\r
-import java.util.Collections\r
-import java.util.HashSet\r
-import java.util.List\r
-import java.util.Set\r
-import java.util.concurrent.Callable\r
-import java.util.concurrent.ExecutorService\r
-import java.util.concurrent.Future\r
-import java.util.concurrent.atomic.AtomicLong\r
-import org.opendaylight.controller.md.sal.common.api.RegistrationListener\r
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus\r
-import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener\r
-import org.opendaylight.controller.md.sal.common.api.data.DataChangePublisher\r
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler\r
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction\r
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration\r
-import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransactionFactory\r
-import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService\r
-import org.opendaylight.controller.md.sal.common.api.data.DataReader\r
-import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification\r
-import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter\r
-import org.opendaylight.controller.sal.common.util.Rpcs\r
-import org.opendaylight.yangtools.concepts.AbstractObjectRegistration\r
-import org.opendaylight.yangtools.concepts.CompositeObjectRegistration\r
-import org.opendaylight.yangtools.concepts.ListenerRegistration\r
-import org.opendaylight.yangtools.concepts.Path\r
-import org.opendaylight.yangtools.concepts.util.ListenerRegistry\r
-import org.opendaylight.yangtools.yang.common.RpcResult\r
-import org.slf4j.LoggerFactory\r
-\r
-import static com.google.common.base.Preconditions.*\rimport 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<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> implements DataModificationTransactionFactory<P, D>, //\r
-DataReader<P, D>, //\r
-DataChangePublisher<P, D, DCL>, //\r
-DataProvisionService<P, D> {\r
-\r
- private static val LOG = LoggerFactory.getLogger(AbstractDataBroker);\r
-\r
- @Property\r
- var ExecutorService executor;\r
-\r
- @Property\r
- var AbstractDataReadRouter<P, D> dataReadRouter;\r
- \r
- @Property\r
- private val AtomicLong submittedTransactionsCount = new AtomicLong;\r
- \r
- @Property\r
- private val AtomicLong failedTransactionsCount = new AtomicLong\r
- \r
- @Property\r
- private val AtomicLong finishedTransactionsCount = new AtomicLong\r
-\r
- Multimap<P, DataChangeListenerRegistration<P, D, DCL>> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.create());\r
- Multimap<P, DataCommitHandlerRegistrationImpl<P, D>> commitHandlers = Multimaps.synchronizedSetMultimap(HashMultimap.create());\r
-
- private val Lock registrationLock = new ReentrantLock;
- \r
- val ListenerRegistry<RegistrationListener<DataCommitHandlerRegistration<P,D>>> commitHandlerRegistrationListeners = new ListenerRegistry();\r
- public new() {\r
- }\r
-\r
- protected def /*Iterator<Entry<Collection<DataChangeListenerRegistration<P,D,DCL>>,D>>*/ affectedCommitHandlers(\r
- HashSet<P> paths) {
- return withLock(registrationLock) [|\r
- return FluentIterable.from(commitHandlers.asMap.entrySet).filter[key.isAffectedBy(paths)] //\r
- .transformAndConcat[value] //\r
- .transform[instance].toList()
- ]\r
- }\r
-\r
- override final readConfigurationData(P path) {\r
- return dataReadRouter.readConfigurationData(path);\r
- }\r
-\r
- override final readOperationalData(P path) {\r
- return dataReadRouter.readOperationalData(path);\r
- }
-
- private static def <T> withLock(Lock lock,Callable<T> method) {
- lock.lock
- try {
- return method.call
- } finally {
- lock.unlock
- }
- } \r
-\r
- override final registerCommitHandler(P path, DataCommitHandler<P, D> commitHandler) {
- return withLock(registrationLock) [|\r
- val registration = new DataCommitHandlerRegistrationImpl(path, commitHandler, this);\r
- commitHandlers.put(path, registration)\r
- LOG.trace("Registering Commit Handler {} for path: {}",commitHandler,path);\r
- for(listener : commitHandlerRegistrationListeners) {\r
- try {\r
- listener.instance.onRegister(registration);\r
- } catch (Exception e) {\r
- LOG.error("Unexpected exception in listener {} during invoking onRegister",listener.instance,e);\r
- }\r
- }
- return registration;
- ]\r
- }\r
-\r
- override final def registerDataChangeListener(P path, DCL listener) {\r
- return withLock(registrationLock) [|
- val reg = new DataChangeListenerRegistration(path, listener, this);\r
- listeners.put(path, reg);\r
- val initialConfig = dataReadRouter.readConfigurationData(path);\r
- val initialOperational = dataReadRouter.readOperationalData(path);\r
- val event = createInitialListenerEvent(path,initialConfig,initialOperational);\r
- listener.onDataChanged(event);\r
- return reg;
- ]\r
- }\r
-\r
- final def registerDataReader(P path, DataReader<P, D> reader) {\r
- return withLock(registrationLock) [|\r
- val confReg = dataReadRouter.registerConfigurationReader(path, reader);\r
- val dataReg = dataReadRouter.registerOperationalReader(path, reader);\r
- \r
- return new CompositeObjectRegistration(reader, Arrays.asList(confReg, dataReg));
- ]\r
- }\r
- \r
- override registerCommitHandlerListener(RegistrationListener<DataCommitHandlerRegistration<P, D>> commitHandlerListener) {\r
- val ret = commitHandlerRegistrationListeners.register(commitHandlerListener);\r
- return ret;\r
- }\r
- \r
- protected def DataChangeEvent<P,D> createInitialListenerEvent(P path,D initialConfig,D initialOperational) {\r
- return new InitialDataChangeEventImpl<P, D>(initialConfig,initialOperational);\r
- \r
- }\r
-\r
- protected final def removeListener(DataChangeListenerRegistration<P, D, DCL> registration) {
- return withLock(registrationLock) [|\r
- listeners.remove(registration.path, registration);
- ]\r
- }\r
-\r
- protected final def removeCommitHandler(DataCommitHandlerRegistrationImpl<P, D> registration) {\r
- return withLock(registrationLock) [|
- commitHandlers.remove(registration.path, registration);\r
- LOG.trace("Removing Commit Handler {} for path: {}",registration.instance,registration.path);\r
- for(listener : commitHandlerRegistrationListeners) {\r
- try {\r
- listener.instance.onUnregister(registration);\r
- } catch (Exception e) {\r
- LOG.error("Unexpected exception in listener {} during invoking onUnregister",listener.instance,e);\r
- }\r
- }
- return null;
- ]\r
- }\r
-\r
- protected final def getActiveCommitHandlers() {\r
- return commitHandlers.entries;\r
- }\r
-\r
- protected def /*Iterator<Entry<Collection<DataChangeListenerRegistration<P,D,DCL>>,D>>*/ affectedListenersWithInitialState(\r
- HashSet<P> paths) {
- return withLock(registrationLock) [|\r
- return FluentIterable.from(listeners.asMap.entrySet).filter[key.isAffectedBy(paths)].transform [\r
- val operationalState = readOperationalData(key)\r
- val configurationState = readConfigurationData(key)\r
- return new ListenerStateCapture(key, value, operationalState, configurationState)\r
- ].toList()
- ]\r
- }\r
-\r
- protected def boolean isAffectedBy(P key, Set<P> paths) {\r
- if (paths.contains(key)) {\r
- return true;\r
- }\r
- for (path : paths) {\r
- if (key.contains(path)) {\r
- return true;\r
- }\r
- }\r
-\r
- return false;\r
- }\r
-\r
- package final def Future<RpcResult<TransactionStatus>> commit(AbstractDataTransaction<P, D> transaction) {\r
- checkNotNull(transaction);\r
- transaction.changeStatus(TransactionStatus.SUBMITED);\r
- val task = new TwoPhaseCommit(transaction, this);\r
- submittedTransactionsCount.andIncrement;\r
- return executor.submit(task);\r
- }\r
-\r
-}\r
-\r
-@Data\r
-package class ListenerStateCapture<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> {\r
-\r
- @Property\r
- P path;\r
-\r
- @Property\r
- Collection<DataChangeListenerRegistration<P, D, DCL>> listeners;\r
-\r
- @Property\r
- D initialOperationalState;\r
-\r
- @Property\r
- D initialConfigurationState;\r
-}\r
-\r
-package class DataChangeListenerRegistration<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> extends AbstractObjectRegistration<DCL> implements ListenerRegistration<DCL> {\r
-\r
- AbstractDataBroker<P, D, DCL> dataBroker;\r
-\r
- @Property\r
- val P path;\r
-\r
- new(P path, DCL instance, AbstractDataBroker<P, D, DCL> broker) {\r
- super(instance)\r
- dataBroker = broker;\r
- _path = path;\r
- }\r
-\r
- override protected removeRegistration() {\r
- dataBroker.removeListener(this);\r
- dataBroker = null;\r
- }\r
-\r
-}\r
-\r
-package class DataCommitHandlerRegistrationImpl<P extends Path<P>, D> //\r
-extends AbstractObjectRegistration<DataCommitHandler<P, D>> //\r
-implements DataCommitHandlerRegistration<P, D> {\r
-\r
- AbstractDataBroker<P, D, ?> dataBroker;\r
-\r
- @Property\r
- val P path;\r
-\r
- new(P path, DataCommitHandler<P, D> instance, AbstractDataBroker<P, D, ?> broker) {\r
- super(instance)\r
- dataBroker = broker;\r
- _path = path;\r
- }\r
-\r
- override protected removeRegistration() {\r
- dataBroker.removeCommitHandler(this);\r
- dataBroker = null;\r
- }\r
-}\r
-\r
-package class TwoPhaseCommit<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> implements Callable<RpcResult<TransactionStatus>> {\r
-\r
- private static val log = LoggerFactory.getLogger(TwoPhaseCommit);\r
-\r
- val AbstractDataTransaction<P, D> transaction;\r
- val AbstractDataBroker<P, D, DCL> dataBroker;\r
- \r
- new(AbstractDataTransaction<P, D> transaction, AbstractDataBroker<P, D, DCL> broker) {\r
- this.transaction = transaction;\r
- this.dataBroker = broker;\r
- }\r
-\r
- override call() throws Exception {\r
-\r
- // get affected paths\r
- val affectedPaths = new HashSet<P>();\r
-\r
- affectedPaths.addAll(transaction.createdConfigurationData.keySet);\r
- affectedPaths.addAll(transaction.updatedConfigurationData.keySet);\r
- affectedPaths.addAll(transaction.removedConfigurationData);\r
-\r
- affectedPaths.addAll(transaction.createdOperationalData.keySet);\r
- affectedPaths.addAll(transaction.updatedOperationalData.keySet);\r
- affectedPaths.addAll(transaction.removedOperationalData);\r
-
- val listeners = dataBroker.affectedListenersWithInitialState(affectedPaths);\r
-\r
- val transactionId = transaction.identifier;\r
-\r
- log.trace("Transaction: {} Started.",transactionId);\r
- log.trace("Transaction: {} Affected Subtrees:",transactionId,affectedPaths);
- // requesting commits\r
- val Iterable<DataCommitHandler<P, D>> commitHandlers = dataBroker.affectedCommitHandlers(affectedPaths);\r
- val List<DataCommitTransaction<P, D>> handlerTransactions = new ArrayList();\r
- try {\r
- for (handler : commitHandlers) {\r
- handlerTransactions.add(handler.requestCommit(transaction));\r
- }\r
- } catch (Exception e) {\r
- log.error("Transaction: {} Request Commit failed", transactionId,e);\r
- dataBroker.failedTransactionsCount.andIncrement\r
- transaction.changeStatus(TransactionStatus.FAILED)
- return rollback(handlerTransactions, e);\r
- }\r
- val List<RpcResult<Void>> results = new ArrayList();\r
- try {\r
- for (subtransaction : handlerTransactions) {\r
- results.add(subtransaction.finish());\r
- }\r
- listeners.publishDataChangeEvent();\r
- } catch (Exception e) {\r
- log.error("Transaction: {} Finish Commit failed",transactionId, e);\r
- dataBroker.failedTransactionsCount.andIncrement
- transaction.changeStatus(TransactionStatus.FAILED)\r
- return rollback(handlerTransactions, e);\r
- }\r
- log.trace("Transaction: {} Finished successfully.",transactionId);\r
- dataBroker.finishedTransactionsCount.andIncrement;
- transaction.changeStatus(TransactionStatus.COMMITED)\r
- return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet());\r
-\r
- }\r
-\r
- def void publishDataChangeEvent(ImmutableList<ListenerStateCapture<P, D, DCL>> listeners) {\r
- dataBroker.executor.submit [|\r
- 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();
- }
- }
- } \r
- ]\r
- }\r
-\r
- def rollback(List<DataCommitTransaction<P, D>> transactions, Exception e) {\r
- for (transaction : transactions) {\r
- transaction.rollback()\r
- }\r
-\r
- // FIXME return encountered error.\r
- return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.emptySet());\r
- }\r
-}\r
-\r
-public abstract class AbstractDataTransaction<P extends Path<P>, D> extends AbstractDataModification<P, D> {\r
-\r
- private static val LOG = LoggerFactory.getLogger(AbstractDataTransaction);
-
- @Property\r
- private val Object identifier;\r
-\r
- var TransactionStatus status;\r
-\r
- var AbstractDataBroker<P, D, ?> broker;\r
-\r
- protected new(Object identifier,AbstractDataBroker<P, D, ?> dataBroker) {\r
- super(dataBroker);\r
- _identifier = identifier;\r
- broker = dataBroker;\r
- status = TransactionStatus.NEW;\r
- LOG.debug("Transaction {} Allocated.", identifier);
-\r
- //listeners = new ListenerRegistry<>();\r
- }\r
-\r
- override commit() {\r
- return broker.commit(this);\r
- }\r
-\r
- override readConfigurationData(P path) {\r
- val local = this.updatedConfigurationData.get(path);\r
- if(local != null) {\r
- return local;\r
- }\r
- \r
- return broker.readConfigurationData(path);\r
- }\r
-\r
- override readOperationalData(P path) {\r
- val local = this.updatedOperationalData.get(path);\r
- if(local != null) {\r
- return local;\r
- }\r
- return broker.readOperationalData(path);\r
- }\r
-\r
- override hashCode() {\r
- return identifier.hashCode;\r
- }\r
-\r
- override equals(Object obj) {\r
- if (this === obj)\r
- return true;\r
- if (obj == null)\r
- return false;\r
- if (getClass() != obj.getClass())\r
- return false;\r
- val other = (obj as AbstractDataTransaction<P,D>);\r
- if (broker == null) {\r
- if (other.broker != null)\r
- return false;\r
- } else if (!broker.equals(other.broker))\r
- return false;\r
- if (identifier == null) {\r
- if (other.identifier != null)\r
- return false;\r
- } else if (!identifier.equals(other.identifier))\r
- return false;\r
- return true;\r
- }\r
-\r
- override TransactionStatus getStatus() {\r
- return status;\r
- }\r
-\r
- protected abstract def void onStatusChange(TransactionStatus status);\r
-\r
- public def changeStatus(TransactionStatus status) {\r
- LOG.debug("Transaction {} transitioned from {} to {}", identifier, this.status, status);
- this.status = status;\r
- onStatusChange(status);\r
- }\r
-\r
-}\r
--- /dev/null
+/**
+ * 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<P extends Path<P>, D extends Object> extends
+ AbstractDataModification<P, D> {
+ 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<P, D, ? extends Object> broker;
+
+ protected AbstractDataTransaction(final Object identifier,
+ final AbstractDataBroker<P, D, ? extends Object> dataBroker) {
+ super(dataBroker);
+ this.identifier = identifier;
+ this.broker = dataBroker;
+ this.status = TransactionStatus.NEW;
+ AbstractDataTransaction.LOG.debug("Transaction {} Allocated.", identifier);
+ }
+
+ @Override
+ public Future<RpcResult<TransactionStatus>> 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);
+ }
+}
private final DataChange<P, D> dataChange;
private final D originalConfigurationSubtree;
-
-
private final D originalOperationalSubtree;
private final D updatedOperationalSubtree;
private final D updatedConfigurationSubtree;
--- /dev/null
+/**
+ * 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<P extends Path<P>, D extends Object, DCL extends DataChangeListener<P, D>> extends
+ AbstractObjectRegistration<DCL> implements ListenerRegistration<DCL> {
+ private AbstractDataBroker<P, D, DCL> dataBroker;
+
+ private final P path;
+
+ public P getPath() {
+ return this.path;
+ }
+
+ public DataChangeListenerRegistration(final P path, final DCL instance, final AbstractDataBroker<P, D, DCL> broker) {
+ super(instance);
+ this.dataBroker = broker;
+ this.path = path;
+ }
+
+ @Override
+ protected void removeRegistration() {
+ this.dataBroker.removeListener(this);
+ this.dataBroker = null;
+ }
+}
--- /dev/null
+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<P extends Path<P>, D> implements DataChangeEvent<P,D> {
+
+ private final D updatedOperationalSubtree;
+ private final Map<P, D> updatedOperational;
+ private final D updatedConfigurationSubtree;
+ private final Map<P, D> updatedConfiguration;
+ private final Set<P> removedOperational;
+ private final Set<P> removedConfiguration;
+ private final D originalOperationalSubtree;
+ private final Map<P, D> originalOperational;
+ private final D originalConfigurationSubtree;
+ private final Map<P, D> originalConfiguration;
+ private final Map<P, D> createdOperational;
+ private final Map<P, D> createdConfiguration;
+
+
+ public ImmutableDataChangeEvent(Builder<P, D> 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<P, D> getCreatedConfigurationData() {
+ return createdConfiguration;
+ }
+
+ @Override
+ public Map<P, D> getCreatedOperationalData() {
+ return createdOperational;
+ }
+
+ @Override
+ public Map<P, D> getOriginalConfigurationData() {
+ return originalConfiguration;
+ }
+ @Override
+ public D getOriginalConfigurationSubtree() {
+ return originalConfigurationSubtree;
+ }
+ @Override
+ public Map<P, D> getOriginalOperationalData() {
+ return originalOperational;
+ }
+ @Override
+ public D getOriginalOperationalSubtree() {
+ return originalOperationalSubtree;
+ }
+ @Override
+ public Set<P> getRemovedConfigurationData() {
+ return removedConfiguration;
+ }
+ @Override
+ public Set<P> getRemovedOperationalData() {
+ return removedOperational;
+ }
+ @Override
+ public Map<P, D> getUpdatedConfigurationData() {
+ return updatedConfiguration;
+ }
+ @Override
+ public D getUpdatedConfigurationSubtree() {
+ return updatedConfigurationSubtree;
+ }
+ @Override
+ public Map<P, D> getUpdatedOperationalData() {
+ return updatedOperational;
+ }
+ @Override
+ public D getUpdatedOperationalSubtree() {
+ return updatedOperationalSubtree;
+ }
+
+ static final <P extends Path<P>,D> Builder<P, D> builder() {
+ return new Builder<>();
+ }
+
+ static final class Builder<P extends Path<P>,D> {
+
+ private D updatedOperationalSubtree;
+ private D originalOperationalSubtree;
+ private D originalConfigurationSubtree;
+ private D updatedConfigurationSubtree;
+
+ private final ImmutableMap.Builder<P, D> updatedOperational = ImmutableMap.builder();
+ private final ImmutableMap.Builder<P, D> updatedConfiguration = ImmutableMap.builder();
+ private final ImmutableSet.Builder<P> removedOperational = ImmutableSet.builder();
+ private final ImmutableSet.Builder<P> removedConfiguration = ImmutableSet.builder();
+ private final ImmutableMap.Builder<P, D> originalOperational = ImmutableMap.builder();
+
+ private final ImmutableMap.Builder<P, D> originalConfiguration = ImmutableMap.builder();
+ private final ImmutableMap.Builder<P, D> createdOperational = ImmutableMap.builder();
+ private final ImmutableMap.Builder<P, D> createdConfiguration = ImmutableMap.builder();
+
+
+ protected Builder<P,D> addTransaction(DataModification<P, D> data, Predicate<P> 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<P, D> addConfigurationChangeSet(RootedChangeSet<P, D> 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<P, D> addOperationalChangeSet(RootedChangeSet<P, D> 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<P, D> build() {
+ return new ImmutableDataChangeEvent<P,D>(this);
+ }
+
+ protected D getUpdatedOperationalSubtree() {
+ return updatedOperationalSubtree;
+ }
+
+ protected Builder<P, D> setUpdatedOperationalSubtree(D updatedOperationalSubtree) {
+ this.updatedOperationalSubtree = updatedOperationalSubtree;
+ return this;
+ }
+
+ protected D getOriginalOperationalSubtree() {
+ return originalOperationalSubtree;
+ }
+
+ protected Builder<P,D> setOriginalOperationalSubtree(D originalOperationalSubtree) {
+ this.originalOperationalSubtree = originalOperationalSubtree;
+ return this;
+ }
+
+ protected D getOriginalConfigurationSubtree() {
+ return originalConfigurationSubtree;
+ }
+
+ protected Builder<P, D> setOriginalConfigurationSubtree(D originalConfigurationSubtree) {
+ this.originalConfigurationSubtree = originalConfigurationSubtree;
+ return this;
+ }
+
+ protected D getUpdatedConfigurationSubtree() {
+ return updatedConfigurationSubtree;
+ }
+
+ protected Builder<P,D> setUpdatedConfigurationSubtree(D updatedConfigurationSubtree) {
+ this.updatedConfigurationSubtree = updatedConfigurationSubtree;
+ return this;
+ }
+
+ protected ImmutableMap.Builder<P, D> getUpdatedOperational() {
+ return updatedOperational;
+ }
+
+ protected ImmutableMap.Builder<P, D> getUpdatedConfiguration() {
+ return updatedConfiguration;
+ }
+
+ protected ImmutableSet.Builder<P> getRemovedOperational() {
+ return removedOperational;
+ }
+
+ protected ImmutableSet.Builder<P> getRemovedConfiguration() {
+ return removedConfiguration;
+ }
+
+ protected ImmutableMap.Builder<P, D> getOriginalOperational() {
+ return originalOperational;
+ }
+
+ protected ImmutableMap.Builder<P, D> getOriginalConfiguration() {
+ return originalConfiguration;
+ }
+
+ protected ImmutableMap.Builder<P, D> getCreatedOperational() {
+ return createdOperational;
+ }
+
+ protected ImmutableMap.Builder<P, D> getCreatedConfiguration() {
+ return createdConfiguration;
+ }
+ }
+
+}
--- /dev/null
+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<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> {
+
+ final P path;
+
+ final Iterable<DataChangeListenerRegistration<P, D, DCL>> listeners;
+
+ D initialOperationalState;
+
+ D initialConfigurationState;
+
+ D finalConfigurationState;
+
+ D finalOperationalState;
+
+ Map<P, D> additionalConfigOriginal;
+ Map<P, D> additionalConfigCreated;
+ Map<P, D> additionalConfigUpdated;
+ Map<P, D> additionalConfigDeleted;
+
+ Map<P, D> additionalOperOriginal;
+ Map<P, D> additionalOperCreated;
+ Map<P, D> additionalOperUpdated;
+ Map<P, D> additionalOperDeleted;
+
+ RootedChangeSet<P, D> normalizedConfigurationChanges;
+ RootedChangeSet<P, D> normalizedOperationalChanges;
+
+ private final Predicate<P> containsPredicate;
+
+ public ListenerStateCapture(P path, Iterable<DataChangeListenerRegistration<P, D, DCL>> listeners,
+ Predicate<P> 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<DataChangeListenerRegistration<P, D, DCL>> 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<P, D> getNormalizedConfigurationChanges() {
+ return normalizedConfigurationChanges;
+ }
+
+ protected void setNormalizedConfigurationChanges(RootedChangeSet<P, D> normalizedConfigurationChanges) {
+ this.normalizedConfigurationChanges = normalizedConfigurationChanges;
+ }
+
+ protected RootedChangeSet<P, D> getNormalizedOperationalChanges() {
+ return normalizedOperationalChanges;
+ }
+
+ protected void setNormalizedOperationalChanges(RootedChangeSet<P, D> normalizedOperationalChange) {
+ this.normalizedOperationalChanges = normalizedOperationalChange;
+ }
+
+ protected DataChangeEvent<P, D> createEvent(DataModification<P, D> modification) {
+ return ImmutableDataChangeEvent.<P, D> builder()//
+ .addTransaction(modification, containsPredicate) //
+ .addConfigurationChangeSet(normalizedConfigurationChanges) //
+ .addOperationalChangeSet(normalizedOperationalChanges) //
+ .setOriginalConfigurationSubtree(initialConfigurationState) //
+ .setOriginalOperationalSubtree(initialOperationalState) //
+ .setUpdatedConfigurationSubtree(finalConfigurationState) //
+ .setUpdatedOperationalSubtree(finalOperationalState) //
+ .build();
+
+ }
+
+}
--- /dev/null
+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<P extends Path<P>,D> {
+
+ private final P root;
+ private final Map<P,D> original;
+ private final Map<P,D> created = new HashMap<>();
+ private final Map<P,D> updated = new HashMap<>();
+ private final Set<P> removed = new HashSet<>();
+
+
+
+ public RootedChangeSet(P root,Map<P, D> original) {
+ super();
+ this.root = root;
+ this.original = original;
+ }
+
+ protected P getRoot() {
+ return root;
+ }
+
+ protected Map<P, D> getOriginal() {
+ return original;
+ }
+
+ protected Map<P, D> getCreated() {
+ return created;
+ }
+
+ protected Map<P, D> getUpdated() {
+ return updated;
+ }
+
+ protected Set<P> getRemoved() {
+ return removed;
+ }
+
+ public void addCreated(Map<P,D> created) {
+ this.created.putAll(created);
+ }
+
+ public void addCreated(Entry<P,D> entry) {
+ created.put(entry.getKey(), entry.getValue());
+ }
+
+ public void addUpdated(Entry<P,D> 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();
+ }
+}
--- /dev/null
+/**
+ * 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<P extends Path<P>, D extends Object, DCL extends DataChangeListener<P, D>> implements
+ Callable<RpcResult<TransactionStatus>> {
+ private final static Logger log = LoggerFactory.getLogger(TwoPhaseCommit.class);
+
+ private final AbstractDataTransaction<P, D> transaction;
+
+ private final AbstractDataBroker<P, D, DCL> dataBroker;
+
+ public TwoPhaseCommit(final AbstractDataTransaction<P, D> transaction, final AbstractDataBroker<P, D, DCL> broker) {
+ this.transaction = transaction;
+ this.dataBroker = broker;
+ }
+
+ @Override
+ public RpcResult<TransactionStatus> call() throws Exception {
+ final Object transactionId = this.transaction.getIdentifier();
+
+ Set<P> changedPaths = ImmutableSet.<P> 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<ListenerStateCapture<P, D, DCL>> listenersBuilder = ImmutableList.builder();
+ listenersBuilder.addAll(dataBroker.affectedListeners(changedPaths));
+ filterProbablyAffectedListeners(dataBroker.probablyAffectedListeners(changedPaths),listenersBuilder);
+
+
+
+ final ImmutableList<ListenerStateCapture<P, D, DCL>> listeners = listenersBuilder.build();
+ final Iterable<DataCommitHandler<P, D>> commitHandlers = dataBroker.affectedCommitHandlers(changedPaths);
+ captureInitialState(listeners);
+
+
+ log.trace("Transaction: {} Starting Request Commit.",transactionId);
+ final List<DataCommitTransaction<P, D>> handlerTransactions = new ArrayList<>();
+ try {
+ for (final DataCommitHandler<P, D> handler : commitHandlers) {
+ DataCommitTransaction<P, D> 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<RpcResult<Void>> results = new ArrayList<RpcResult<Void>>();
+ try {
+ for (final DataCommitTransaction<P, D> 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.<TransactionStatus> getRpcResult(true, TransactionStatus.COMMITED,
+ Collections.<RpcError> emptySet());
+ }
+
+ private void captureInitialState(ImmutableList<ListenerStateCapture<P, D, DCL>> listeners) {
+ for (ListenerStateCapture<P, D, DCL> state : listeners) {
+ state.setInitialConfigurationState(dataBroker.readConfigurationData(state.getPath()));
+ state.setInitialOperationalState(dataBroker.readOperationalData(state.getPath()));
+ }
+ }
+
+
+ private void captureFinalState(ImmutableList<ListenerStateCapture<P, D, DCL>> listeners) {
+ for (ListenerStateCapture<P, D, DCL> state : listeners) {
+ state.setFinalConfigurationState(dataBroker.readConfigurationData(state.getPath()));
+ state.setFinalOperationalState(dataBroker.readOperationalData(state.getPath()));
+ }
+ }
+
+ private void filterProbablyAffectedListeners(
+ ImmutableList<ListenerStateCapture<P, D, DCL>> probablyAffectedListeners, Builder<ListenerStateCapture<P, D, DCL>> reallyAffected) {
+
+ for(ListenerStateCapture<P, D, DCL> listenerSet : probablyAffectedListeners) {
+ P affectedPath = listenerSet.getPath();
+ Optional<RootedChangeSet<P,D>> configChange = resolveConfigChange(affectedPath);
+ Optional<RootedChangeSet<P, D>> 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<RootedChangeSet<P, D>> resolveOperChange(P affectedPath) {
+ Map<P, D> originalOper = dataBroker.deepGetBySubpath(transaction.getOriginalOperationalData(),affectedPath);
+ Map<P, D> createdOper = dataBroker.deepGetBySubpath(transaction.getCreatedOperationalData(),affectedPath);
+ Map<P, D> updatedOper = dataBroker.deepGetBySubpath(transaction.getUpdatedOperationalData(),affectedPath);
+ Set<P> removedOper = Sets.filter(transaction.getRemovedOperationalData(), dataBroker.createIsContainedPredicate(affectedPath));
+ return resolveChanges(affectedPath,originalOper,createdOper,updatedOper,removedOper);
+ }
+
+ private Optional<RootedChangeSet<P, D>> resolveConfigChange(P affectedPath) {
+ Map<P, D> originalConfig = dataBroker.deepGetBySubpath(transaction.getOriginalConfigurationData(),affectedPath);
+ Map<P, D> createdConfig = dataBroker.deepGetBySubpath(transaction.getCreatedConfigurationData(),affectedPath);
+ Map<P, D> updatedConfig = dataBroker.deepGetBySubpath(transaction.getUpdatedConfigurationData(),affectedPath);
+ Set<P> removedConfig = Sets.filter(transaction.getRemovedConfigurationData(), dataBroker.createIsContainedPredicate(affectedPath));
+ return resolveChanges(affectedPath,originalConfig,createdConfig,updatedConfig,removedConfig);
+ }
+
+ private Optional<RootedChangeSet<P,D>> resolveChanges(P affectedPath, Map<P, D> originalConfig, Map<P, D> createdConfig, Map<P, D> updatedConfig,Set<P> potentialDeletions) {
+ Predicate<P> isContained = dataBroker.createIsContainedPredicate(affectedPath);
+
+ if(createdConfig.isEmpty() && updatedConfig.isEmpty() && potentialDeletions.isEmpty()) {
+ return Optional.absent();
+ }
+ RootedChangeSet<P, D> changeSet = new RootedChangeSet<P,D>(affectedPath,originalConfig);
+ changeSet.addCreated(createdConfig);
+
+ for(Entry<P, D> entry : updatedConfig.entrySet()) {
+ if(originalConfig.containsKey(entry.getKey())) {
+ changeSet.addUpdated(entry);
+ } else {
+ changeSet.addCreated(entry);
+ }
+ }
+
+ for(Entry<P,D> 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<ListenerStateCapture<P, D, DCL>> listeners) {
+ ExecutorService executor = this.dataBroker.getExecutor();
+ final Runnable notifyTask = new Runnable() {
+ @Override
+ public void run() {
+ for (final ListenerStateCapture<P, D, DCL> listenerSet : listeners) {
+ {
+ DataChangeEvent<P, D> changeEvent = listenerSet.createEvent(transaction);
+ for (final DataChangeListenerRegistration<P, D, DCL> listener : listenerSet.getListeners()) {
+ try {
+ listener.getInstance().onDataChanged(changeEvent);
+ } catch (Exception e) {
+ log.error("Unhandled exception when invoking listener {}", listener);
+ }
+ }
+ }
+ }
+ }
+ };
+ executor.submit(notifyTask);
+ }
+
+ public RpcResult<TransactionStatus> rollback(final List<DataCommitTransaction<P, D>> transactions, final Exception e) {
+ for (final DataCommitTransaction<P, D> transaction : transactions) {
+ transaction.rollback();
+ }
+ Set<RpcError> _emptySet = Collections.<RpcError> emptySet();
+ return Rpcs.<TransactionStatus> getRpcResult(false, TransactionStatus.FAILED, _emptySet);
+ }
+}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
- <version>${project.version}</version>
</dependency>
</dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
-
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
- <version>5.0.0</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-public interface RpcProvisionRegistry extends BrokerService, RouteChangePublisher<RpcRoutingContext, InstanceIdentifier> {
+public interface RpcProvisionRegistry extends RpcImplementation, BrokerService, RouteChangePublisher<RpcRoutingContext, InstanceIdentifier> {
/**
* Registers an implementation of the rpc.
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-spi</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<build>
<plugins>
+ <!-- TODO - unite yang-maven-plugin configuration in md-sal-->
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
return session;
}
- protected def Future<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
+ protected def Future<RpcResult<CompositeNode>> invokeRpcAsync(QName rpc, CompositeNode input) {
val result = executor.submit([|router.invokeRpc(rpc, input)] as Callable<RpcResult<CompositeNode>>);
return result;
}
override <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> registerRouteChangeListener(L listener) {
return router.registerRouteChangeListener(listener);
}
+
+ override invokeRpc(QName rpc,CompositeNode input){
+ return router.invokeRpc(rpc,input)
+ }
+
+ override getSupportedRpcs() {
+ return router.getSupportedRpcs();
+ }
}
}
override rpc(QName rpc, CompositeNode input) {
- return broker.invokeRpc(rpc, input);
+ return broker.invokeRpcAsync(rpc, input);
}
override <T extends BrokerService> T getService(Class<T> service) {
L listener) {
return rpcs.registerRouteChangeListener(listener);
}
+
+
}
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;
public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataStore> implements //
DataStore, //
SchemaServiceListener, //
+ SchemaContextListener, //
AutoCloseable {
private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class);
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<RpcProvisionRegistry>
implements RpcProvisionRegistry {
public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(L listener) {
return getDelegate().registerRouteChangeListener(listener);
}
+
+
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ return getDelegate().getSupportedRpcs();
+ }
+
+ @Override
+ public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+ return getDelegate().invokeRpc(rpc,input);
+ }
}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-threadgroup-config</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<groupId>org.opendaylight.controller</groupId>
<artifactId>logback-config</artifactId>
<scope>test</scope>
- <version>${netconf.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>ietf-netconf-monitoring</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>ietf-inet-types</artifactId>
- <version>2010.09.24.3</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>threadpool-config-api</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netty-config-api</artifactId>
- <version>0.2.4-SNAPSHOT</version>
</dependency>
</dependencies>
*/
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;
public void prepare() {
for (InstanceIdentifier toRemove : modification.getRemovedConfigurationData()) {
- sendRemove(toRemove);
+ sendDelete(toRemove);
}
for(Entry<InstanceIdentifier, CompositeNode> toUpdate : modification.getUpdatedConfigurationData().entrySet()) {
sendMerge(toUpdate.getKey(),toUpdate.getValue());
sendEditRpc(createEditStructure(key, Optional.<String>absent(), Optional.of(value)));
}
- private void sendRemove(InstanceIdentifier toRemove) {
- sendEditRpc(createEditStructure(toRemove, Optional.of("remove"), Optional.<CompositeNode> absent()));
+ private void sendDelete(InstanceIdentifier toDelete) {
+ sendEditRpc(createEditStructure(toDelete, Optional.of("delete"), Optional.<CompositeNode> absent()));
}
private void sendEditRpc(CompositeNode editStructure) {
return ret;
}
- private CompositeNode createEditStructure(InstanceIdentifier dataPath, Optional<String> action,
+ private CompositeNode createEditStructure(InstanceIdentifier dataPath, Optional<String> operation,
Optional<CompositeNode> lastChildOverride) {
List<PathArgument> path = dataPath.getPath();
List<PathArgument> reversed = Lists.reverse(path);
}
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<Node<?>> children = lastChildOverride.get().getChildren();
}
@Override
- public RpcResult<Void> finish() throws IllegalStateException {
+ public RpcResult<Void> finish() {
CompositeNodeBuilder<ImmutableCompositeNode> commitInput = ImmutableCompositeNode.builder();
commitInput.setQName(NETCONF_COMMIT_QNAME);
RpcResult<?> rpcResult = device.invokeRpc(NetconfMapping.NETCONF_COMMIT_QNAME, commitInput.toInstance());
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 {
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");
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)
}
}
static def NetconfMessage toRpcMessage(QName rpc, CompositeNode node,Optional<SchemaContext> 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);
}
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>sal-remote</artifactId>
- <packaging>jar</packaging>
+ <packaging>bundle</packaging>
<scm>
<connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
<developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
<url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
<tag>HEAD</tag>
</scm>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-api</artifactId>
+ <version>1.1-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
<build>
<plugins>
<plugin>
</plugin>
</plugins>
</build>
-
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
- </dependency>
- </dependencies>
</project>
+++ /dev/null
-/*
- * 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<RpcResult<BeginTransactionOutput>> beginTransaction() {
- return null;
- }
-
- @Override
- public Future<RpcResult<CreateDataChangeEventSubscriptionOutput>> createDataChangeEventSubscription(CreateDataChangeEventSubscriptionInput input) {
- return null;
- }
-
- @Override
- public Future<RpcResult<CreateNotificationStreamOutput>> createNotificationStream(CreateNotificationStreamInput input) {
- return null;
- }
-}
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
- <version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
- <version>4.0.10.Final</version>
</dependency>
<!-- Testing Dependencies -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <version>1.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>sal-restconf-broker</artifactId>
- <packaging>jar</packaging>
+ <packaging>bundle</packaging>
<scm>
<connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
<developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
<url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
<tag>HEAD</tag>
</scm>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- </plugin>
- </plugins>
- </build>
-
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-util</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-remote</artifactId>
- <version>1.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-broker-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-config</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>restconf-client-api</artifactId>
- <version>${yangtools.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>restconf-client-impl</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
</dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+ <Import-Package>
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.8</version>
+ <executions>
+ <execution>
+ <id>add-source</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>${project.build.directory}/generated-sources/</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
</project>
+++ /dev/null
-/*
- * 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 <T extends Notification> void addNotificationListener(Class<T> notificationType, NotificationListener<T> 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 <T extends Notification> void removeNotificationListener(Class<T> notificationType, NotificationListener<T> listener) {
-
- }
-
- @Override
- public <T extends Notification> Registration<NotificationListener<T>> registerNotificationListener(Class<T> notificationType, NotificationListener<T> listener) {
- //TODO implementation using sal-remote
- return null;
- }
-
- @Override
- public Registration<org.opendaylight.yangtools.yang.binding.NotificationListener> registerNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
- //TODO implementation using sal-remote
- return null;
- }
-}
* 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;
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<BindingAwareService> 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.<BindingAwareService> 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);
}
+
}
--- /dev/null
+/*
+ * 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<InstanceIdentifier<? extends DataObject>,DataObject> {
+ private final Map<InstanceIdentifier<?>, DataObject> createdConfig, createdOper, origConfig, origOper, updatedConfig, updatedOper;
+ private final Set<InstanceIdentifier<?>> removedConfig, removedOper;
+
+ public RemoteDataChangeEvent(DataChangedNotification dataChangedNotification) {
+ final Map<InstanceIdentifier<?>, DataObject> createdConfig = new HashMap<>();
+ final Map<InstanceIdentifier<?>, DataObject> createdOper = new HashMap<>();
+ final Map<InstanceIdentifier<?>, DataObject> origConfig = new HashMap<>();
+ final Map<InstanceIdentifier<?>, DataObject> origOper = new HashMap<>();
+ final Map<InstanceIdentifier<?>, DataObject> updatedConfig = new HashMap<>();
+ final Map<InstanceIdentifier<?>, DataObject> updatedOper = new HashMap<>();
+ final Set<InstanceIdentifier<?>> removedConfig = new HashSet<>();
+ final Set<InstanceIdentifier<?>> 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<InstanceIdentifier<?>, DataObject> getCreatedOperationalData() {
+ return createdOper;
+ }
+
+ @Override
+ public Map<InstanceIdentifier<?>, DataObject> getCreatedConfigurationData() {
+ return createdConfig;
+ }
+
+ @Override
+ public Map<InstanceIdentifier<?>, DataObject> getUpdatedOperationalData() {
+ return updatedOper;
+ }
+
+ @Override
+ public Map<InstanceIdentifier<?>, DataObject> getUpdatedConfigurationData() {
+ return updatedConfig;
+ }
+
+ @Override
+ public Set<InstanceIdentifier<?>> getRemovedConfigurationData() {
+ return removedConfig;
+ }
+
+ @Override
+ public Set<InstanceIdentifier<?>> getRemovedOperationalData() {
+ return removedOper;
+ }
+
+ @Override
+ public Map<InstanceIdentifier<?>, DataObject> getOriginalConfigurationData() {
+ return origConfig;
+ }
+
+ @Override
+ public Map<InstanceIdentifier<?>, DataObject> getOriginalOperationalData() {
+ return origOper;
+ }
+}
--- /dev/null
+/*
+ * 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 extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
+ throw new UnsupportedOperationException("Deprecated");
+ }
+
+ @Override
+ public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
+ throw new UnsupportedOperationException("Deprecated");
+ }
+
+ @Override
+ public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
+ throw new UnsupportedOperationException("Deprecated");
+ }
+
+ @Override
+ public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
+ throw new UnsupportedOperationException("Deprecated");
+ }
+
+ @Override
+ public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
+ throw new UnsupportedOperationException("Deprecated");
+ }
+
+ @Override
+ public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
+ throw new UnsupportedOperationException("Deprecated");
+ }
+
+ @Override
+ public DataObject getData(InstanceIdentifier<? extends DataObject> data) {
+ throw new UnsupportedOperationException("Deprecated");
+ }
+
+ @Override
+ public DataObject getConfigurationData(InstanceIdentifier<?> data) {
+ throw new UnsupportedOperationException("Deprecated");
+ }
+
+ @Override
+ public DataModificationTransaction beginTransaction() {
+ Future<RpcResult<BeginTransactionOutput>> rpcResultFuture = this.salRemoteService.beginTransaction();
+ //TODO finish yang model for proper remoteDataModificationTransaction setup
+ RemoteDataModificationTransaction remoteDataModificationTransaction = new RemoteDataModificationTransaction();
+ return remoteDataModificationTransaction;
+ }
+
+ @Override
+ public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
+ throw new UnsupportedOperationException("Deprecated");
+ }
+
+ @Override
+ public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
+ throw new UnsupportedOperationException("Deprecated");
+ }
+
+ @Override
+ public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
+ try {
+ Optional<DataObject> optDataObject = (Optional<DataObject>) 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<? extends DataObject> path) {
+ try {
+ Optional<DataObject> optDataObject = (Optional<DataObject>) 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<DataChangeListener> registerDataChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener listener) {
+ CreateDataChangeEventSubscriptionInputBuilder inputBuilder = new CreateDataChangeEventSubscriptionInputBuilder();
+ Future<RpcResult<CreateDataChangeEventSubscriptionOutput>> 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<String,EventStreamInfo> 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<DataChangeListener> {
+ private DataChangeListener dataChangeListener;
+ public SalRemoteDataListenerRegistration(DataChangeListener dataChangeListener){
+ this.dataChangeListener = dataChangeListener;
+ }
+ @Override
+ public DataChangeListener getInstance() {
+ return this.dataChangeListener;
+ }
+ @Override
+ public void close() throws Exception {
+ //noop
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<Class<? extends Notification>,NotificationListener<? extends Object>> listeners;
+ private ExecutorService _executor;
+
+ public NotificationServiceImpl(RestconfClientContext restconfClienetContext){
+ this.restconfClientContext = restconfClienetContext;
+ this.salRemoteService = this.restconfClientContext.getRpcServiceContext(SalRemoteService.class).getRpcService();
+
+ HashMultimap<Class<? extends Notification>,NotificationListener<? extends Object>> _create = HashMultimap.<Class<? extends Notification>, NotificationListener<? extends Object>>create();
+ SetMultimap<Class<? extends Notification>,NotificationListener<? extends Object>> _synchronizedSetMultimap = Multimaps.<Class<? extends Notification>, NotificationListener<? extends Object>>synchronizedSetMultimap(_create);
+ this.listeners = _synchronizedSetMultimap;
+
+ }
+ public ExecutorService getExecutor() {
+ return this._executor;
+ }
+
+ public void setExecutor(final ExecutorService executor) {
+ this._executor = executor;
+ }
+
+ @Override
+ public <T extends Notification> void addNotificationListener(Class<T> notificationType, NotificationListener<T> 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 <T extends Notification> void removeNotificationListener(Class<T> notificationType, NotificationListener<T> listener) {
+ this.listeners.remove(notificationType, listener);
+ }
+
+ @Override
+ public <T extends Notification> Registration<NotificationListener<T>> registerNotificationListener(Class<T> notificationType, NotificationListener<T> listener) {
+ //TODO implementation using sal-remote
+ List<QName> notifications = new ArrayList<QName>();
+ notifications.add(new QName(notificationType.toString()));
+ String notificationStreamName = RemoteStreamTools.createNotificationStream(salRemoteService, notifications);
+ final Map<String,EventStreamInfo> desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext, notificationStreamName);
+ RemoteNotificationListener remoteNotificationListener = new RemoteNotificationListener(listener);
+ ListenerRegistration<?> listenerRegistration = restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(remoteNotificationListener);
+ return new SalNotificationRegistration<T>(listenerRegistration);
+ }
+
+ @Override
+ public Registration<org.opendaylight.yangtools.yang.binding.NotificationListener> registerNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
+ //TODO implementation using sal-remote
+ String notificationStreamName = RemoteStreamTools.createNotificationStream(salRemoteService, null);
+ final Map<String,EventStreamInfo> desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext, notificationStreamName);
+ return restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(listener);
+ }
+
+ private class SalNotificationRegistration<T extends Notification> implements Registration<NotificationListener<T>>{
+ private final Registration<?> registration;
+
+ public SalNotificationRegistration(ListenerRegistration<?> listenerRegistration){
+ this.registration = listenerRegistration;
+ }
+
+ @Override
+ public NotificationListener<T> getInstance() {
+ return this.getInstance();
+ }
+
+ @Override
+ public void close() throws Exception {
+ this.registration.close();
+ }
+ }
+
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
* 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 extends RpcService> T getRpcService(Class<T> module) {
- //TODO implementation using restconf-client
- return null;
+ return restconfClientContext.getRpcServiceContext(module).getRpcService();
}
}
--- /dev/null
+/*
+ * 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));
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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<QName> notifications){
+ CreateNotificationStreamInputBuilder notificationStreamInputBuilder = new CreateNotificationStreamInputBuilder();
+
+ if (null == notifications){
+ notificationStreamInputBuilder.setNotifications(notifications);
+ }
+
+ Future<RpcResult<CreateNotificationStreamOutput>> 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<String,EventStreamInfo> createEventStream(RestconfClientContext restconfClientContext, String desiredStreamName){
+ ListenableFuture<Set<EventStreamInfo>> availableEventStreams = restconfClientContext.getAvailableEventStreams();
+ final Map<String,EventStreamInfo> desiredEventStream = new HashMap<String,EventStreamInfo>();
+
+ try {
+ Iterator<EventStreamInfo> 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;
+ }
+}
--- /dev/null
+/*
+ * 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<? extends DataObject> path, DataObject data) {
+
+ }
+
+ @Override
+ public void putOperationalData(InstanceIdentifier<? extends DataObject> path, DataObject data) {
+
+ }
+
+ @Override
+ public void putConfigurationData(InstanceIdentifier<? extends DataObject> path, DataObject data) {
+
+ }
+
+ @Override
+ public void removeRuntimeData(InstanceIdentifier<? extends DataObject> path) {
+
+ }
+
+ @Override
+ public void removeOperationalData(InstanceIdentifier<? extends DataObject> path) {
+
+ }
+
+ @Override
+ public void removeConfigurationData(InstanceIdentifier<? extends DataObject> path) {
+
+ }
+
+ @Override
+ public Future<RpcResult<TransactionStatus>> commit() {
+ return null;
+ }
+
+ @Override
+ public ListenerRegistration<DataTransactionListener> registerListener(DataTransactionListener listener) {
+ return null;
+ }
+
+ @Override
+ public Map<InstanceIdentifier<? extends DataObject>, DataObject> getCreatedOperationalData() {
+ return null;
+ }
+
+ @Override
+ public Map<InstanceIdentifier<? extends DataObject>, DataObject> getCreatedConfigurationData() {
+ return null;
+ }
+
+ @Override
+ public Map<InstanceIdentifier<? extends DataObject>, DataObject> getUpdatedOperationalData() {
+ return null;
+ }
+
+ @Override
+ public Map<InstanceIdentifier<? extends DataObject>, DataObject> getUpdatedConfigurationData() {
+ return null;
+ }
+
+ @Override
+ public Set<InstanceIdentifier<? extends DataObject>> getRemovedConfigurationData() {
+ return null;
+ }
+
+ @Override
+ public Set<InstanceIdentifier<? extends DataObject>> getRemovedOperationalData() {
+ return null;
+ }
+
+ @Override
+ public Map<InstanceIdentifier<? extends DataObject>, DataObject> getOriginalConfigurationData() {
+ return null;
+ }
+
+ @Override
+ public Map<InstanceIdentifier<? extends DataObject>, DataObject> getOriginalOperationalData() {
+ return null;
+ }
+
+ @Override
+ public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
+ return null;
+ }
+
+ @Override
+ public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
+ return null;
+ }
+}
--- /dev/null
+/*
+ * 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){
+
+ }
+}
--- /dev/null
+/*
+ * 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){
+
+ }
+}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-statistics</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-base</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.xtend</groupId>
--- /dev/null
+/*
+ * 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<I, K> extends AbstractStatsTracker<I, K> 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<I, K> {
+ private static final Logger logger = LoggerFactory.getLogger(AbstractStatsTracker.class);
+ private final FutureCallback<RpcResult<? extends TransactionAware>> callback =
+ new FutureCallback<RpcResult<? extends TransactionAware>>() {
+ @Override
+ public void onSuccess(RpcResult<? extends TransactionAware> 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<K, Long> 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<Node> getNodeIdentifierBuilder() {
+ return InstanceIdentifier.builder(getNodeIdentifier());
+ }
+
+ protected final NodeRef getNodeRef() {
+ return context.getNodeRef();
+ }
+
+ protected final InstanceIdentifier<Node> getNodeIdentifier() {
+ return context.getNodeIdentifier();
+ }
+
+ protected final <T extends TransactionAware> void requestHelper(Future<RpcResult<T>> 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<I> 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<Entry<K, Long>> it = trackedItems.entrySet().iterator();it.hasNext();){
+ Entry<K, Long> e = it.next();
+ if (now > e.getValue()) {
+ cleanupSingleStat(trans, e.getKey());
+ it.remove();
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<Node> getNodeIdentifier();
+ NodeRef getNodeRef();
+ DataModificationTransaction startDataModification();
+ void registerTransaction(TransactionId id);
+ void registerTableTransaction(TransactionId id, Short tableId);
+}
--- /dev/null
+/*
+ * 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<FlowCapableNode> root;
+ private final StatisticsProvider stats;
+
+ private final Predicate<InstanceIdentifier<?>> filterIdentifiers = new Predicate<InstanceIdentifier<?>>() {
+ @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<FlowCapableNode> 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<InstanceIdentifier<?>, 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<NodeKey> removedNodes =
+ Collections2.filter(Collections2.transform(
+ Sets.filter(change.getRemovedOperationalData(), filterIdentifiers),
+ new Function<InstanceIdentifier<?>, 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<NodeKey> addedNodes =
+ Collections2.filter(Collections2.transform(
+ Sets.filter(change.getCreatedOperationalData().keySet(), filterIdentifiers),
+ new Function<InstanceIdentifier<?>, 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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<FlowAndStatisticsMapList, FlowStatsEntry> {
+ 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<Table> 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<Flow> 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<Flow> 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<Flow> 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<InstanceIdentifier<?>, DataObject> change) {
+ for (Entry<InstanceIdentifier<?>, 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> flow = (InstanceIdentifier<Flow>)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);
+ }
+}
--- /dev/null
+/*
+ * 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<FlowTableAndStatisticsMap, FlowTableAndStatisticsMap> {
+ private final Set<TableKey> privateTables = new ConcurrentSkipListSet<>();
+ private final Set<TableKey> tables = Collections.unmodifiableSet(privateTables);
+ private final OpendaylightFlowTableStatisticsService flowTableStatsService;
+
+ FlowTableStatsTracker(OpendaylightFlowTableStatisticsService flowTableStatsService, final FlowCapableContext context, long lifetimeNanos) {
+ super(context, lifetimeNanos);
+ this.flowTableStatsService = flowTableStatsService;
+ }
+
+ Set<TableKey> 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<Table> 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()));
+ }
+ }
+}
--- /dev/null
+/*
+ * 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<GroupDescStats, GroupDescStats> {
+ 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<Group> 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<NodeGroupDescStats> 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<InstanceIdentifier<?>, 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> group = (InstanceIdentifier<Group>)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);
+ }
+}
--- /dev/null
+/*
+ * 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<GroupStats, GroupStats> {
+ 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<NodeGroupStatistics> 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<Group> 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<InstanceIdentifier<?>, DataObject> change) {
+ final DataModificationTransaction trans = startTransaction();
+ for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+ if (Group.class.equals(key.getTargetType())) {
+ @SuppressWarnings("unchecked")
+ InstanceIdentifier<Group> group = (InstanceIdentifier<Group>)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);
+ }
+}
--- /dev/null
+/*
+ * 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<MeterConfigStats, MeterConfigStats> {
+ 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<NodeMeterConfigStats> 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<Meter> 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<InstanceIdentifier<?>, DataObject> change) {
+ final DataModificationTransaction trans = startTransaction();
+
+ for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+ if (Meter.class.equals(key.getTargetType())) {
+ @SuppressWarnings("unchecked")
+ InstanceIdentifier<Meter> meter = (InstanceIdentifier<Meter>)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);
+ }
+}
--- /dev/null
+/*
+ * 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<MeterStats, MeterStats> {
+ 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<NodeMeterStatistics> 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<Meter> 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<InstanceIdentifier<?>, 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> meter = (InstanceIdentifier<Meter>)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);
+ }
+}
*/
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<TxIdEntry,Date> txIdToRequestTypeMap = new ConcurrentHashMap<TxIdEntry,Date>();
+ private final Map<TxIdEntry,Long> 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<TxIdEntry,Short> txIdTotableIdMap = new ConcurrentHashMap<TxIdEntry,Short>();
-
- private final int NUMBER_OF_WAIT_CYCLES =2;
+ private final Map<TxIdEntry,Short> 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;
}
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;
}
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<TxIdEntry> 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);
- }
+ }
}
}
}
--- /dev/null
+/*
+ * 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<NodeConnectorStatisticsAndPortNumberMap, NodeConnectorStatisticsAndPortNumberMap> {
+ 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<NodeConnector> 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()));
+ }
+ }
+}
*/
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;
*
* @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<GroupDescStats,Long> groupDescStatsUpdate = new HashMap<>();
- private final Map<MeterConfigStats,Long> meterConfigStatsUpdate = new HashMap<>();
- private final Map<FlowEntry,Long> flowStatsUpdate = new HashMap<>();
- private final Map<QueueEntry,Long> queuesStatsUpdate = new HashMap<>();
+ private final MultipartMessageManager msgManager;
private final InstanceIdentifier<Node> 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<GroupDescStats> 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<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
- .augmentation(FlowCapableNode.class)
- .child(Group.class,groupKey).toInstance();
+ @Override
+ public InstanceIdentifier<Node> 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<GroupDescStats> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ groupDescStats.updateStats(list);
}
-
- trans.commit();
}
-
- public synchronized void updateGroupStats(List<GroupStats> list) {
- final DataModificationTransaction trans = statisticsProvider.startChange();
-
- for(GroupStats groupStats : list) {
- GroupBuilder groupBuilder = new GroupBuilder();
- GroupKey groupKey = new GroupKey(groupStats.getGroupId());
- groupBuilder.setKey(groupKey);
-
- InstanceIdentifier<Group> 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<GroupStats> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ groupStats.updateStats(list);
}
-
- trans.commit();
}
- public synchronized void updateMeterConfigStats(List<MeterConfigStats> 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<Meter> 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<MeterConfigStats> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ meterConfigStats.updateStats(list);
}
-
- trans.commit();
}
-
- public synchronized void updateMeterStats(List<MeterStats> list) {
- final DataModificationTransaction trans = statisticsProvider.startChange();
-
- for(MeterStats meterStats : list) {
- MeterBuilder meterBuilder = new MeterBuilder();
- MeterKey meterKey = new MeterKey(meterStats.getMeterId());
- meterBuilder.setKey(meterKey);
-
- InstanceIdentifier<Meter> 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<MeterStats> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ meterStats.updateStats(list);
}
-
- trans.commit();
}
- public synchronized void updateQueueStats(List<QueueIdAndStatisticsMap> 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<Queue> 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<QueueIdAndStatisticsMap> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ queueStats.updateStats(list);
}
-
- trans.commit();
}
- public synchronized void updateFlowTableStats(List<FlowTableAndStatisticsMap> list) {
- final DataModificationTransaction trans = statisticsProvider.startChange();
-
- for (FlowTableAndStatisticsMap ftStats : list) {
-
- InstanceIdentifier<Table> 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<FlowTableAndStatisticsMap> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ flowTableStats.updateStats(list);
}
-
- trans.commit();
}
- public synchronized void updateNodeConnectorStats(List<NodeConnectorStatisticsAndPortNumberMap> 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<NodeConnector> 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<NodeConnectorStatisticsAndPortNumberMap> 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<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
.augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
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<FlowAndStatisticsMapList> 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);
}
public synchronized void updateMeterFeatures(MeterFeatures features) {
- final DataModificationTransaction trans = statisticsProvider.startChange();
+ final DataModificationTransaction trans = dps.beginTransaction();
final NodeBuilder nodeData = new NodeBuilder();
nodeData.setKey(targetNodeKey);
trans.commit();
}
- public synchronized void updateFlowStats(List<FlowAndStatisticsMapList> 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<Table> 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<Flow> 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<Flow> 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<Flow> 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<Entry<GroupDescStats, Long>> it = this.groupDescStatsUpdate.entrySet().iterator();it.hasNext();){
- Entry<GroupDescStats, Long> 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<TableKey> 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<Entry<MeterConfigStats, Long>> it = this.meterConfigStatsUpdate.entrySet().iterator();it.hasNext();){
- Entry<MeterConfigStats, Long> 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<Entry<FlowEntry, Long>> it = this.flowStatsUpdate.entrySet().iterator();it.hasNext();){
- Entry<FlowEntry, Long> 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<Entry<QueueEntry, Long>> it = this.queuesStatsUpdate.entrySet().iterator();it.hasNext();){
- Entry<QueueEntry, Long> 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<Meter> 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<Group> 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);
}
}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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<QueueIdAndStatisticsMap, QueueStatsEntry> {
+ 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<Queue> 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<InstanceIdentifier<?>, DataObject> change) {
+ for (Entry<InstanceIdentifier<?>, 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> queue = (InstanceIdentifier<Queue>)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);
+ }
+}
--- /dev/null
+/*
+ * 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<RpcError> errors;
+
+ public RPCFailedException(final String message, final Collection<RpcError> errors) {
+ super(message);
+ this.errors = errors;
+ }
+
+ @Override
+ public String toString() {
+ return "RPCFailedException [errors=" + errors + ", message=" + getMessage() + ']';
+ }
+}
private final static Logger sucLogger = LoggerFactory.getLogger(StatisticsListener.class);
private final StatisticsProvider statisticsManager;
- private final MultipartMessageManager messageManager;
/**
* default ctor
*/
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());
}
}
@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());
}
}
}
-
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;
@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
*/
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;
*
*/
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<Nodes> nodesIdentifier = InstanceIdentifier.builder(Nodes.class).toInstance();
+ private final ConcurrentMap<NodeId, NodeStatisticsHandler> handlers = new ConcurrentHashMap<>();
+ private final Timer timer = new Timer("statistics-manager", true);
private final DataProviderService dps;
- //Local caching of stats
- private final ConcurrentMap<NodeId,NodeStatisticsHandler> statisticsCache = new ConcurrentHashMap<>();
-
private OpendaylightGroupStatisticsService groupStatsService;
private OpendaylightMeterStatisticsService meterStatsService;
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<NotificationListener> listenerRegistration;
- public void start(final DataBrokerService dbs, final NotificationProviderService nps, final RpcConsumerRegistry rpcRegistry) {
-
- this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter);
+ private ListenerRegistration<DataChangeListener> 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);
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<FlowCapableNode> 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<? extends DataObject> pathNode = InstanceIdentifier.builder(Nodes.class)
- .child(Node.class).toInstance();
- dbs.registerDataChangeListener(pathNode, statsUpdateHandler);
-
- //Register for flow updates
- InstanceIdentifier<? extends DataObject> 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<? extends DataObject> pathMeter = InstanceIdentifier.builder(Nodes.class).child(Node.class)
- .augmentation(FlowCapableNode.class)
- .child(Meter.class).toInstance();
-
- dbs.registerDataChangeListener(pathMeter, statsUpdateHandler);
-
- //Register for group updates
- InstanceIdentifier<? extends DataObject> pathGroup = InstanceIdentifier.builder(Nodes.class).child(Node.class)
- .augmentation(FlowCapableNode.class)
- .child(Group.class).toInstance();
- dbs.registerDataChangeListener(pathGroup, statsUpdateHandler);
-
- //Register for queue updates
- InstanceIdentifier<? extends DataObject> 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<Node> 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<Node> 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<RpcResult<GetFlowTablesStatisticsOutput>> 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<RpcResult<GetAllFlowsStatisticsFromAllFlowTablesOutput>> 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<RpcResult<GetFlowStatisticsFromFlowTableOutput>> 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<Short> 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<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> 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<RpcResult<GetAllNodeConnectorsStatisticsOutput>> 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<RpcResult<GetAllGroupStatisticsOutput>> 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<RpcResult<GetGroupDescriptionOutput>> 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<RpcResult<GetAllMeterStatisticsOutput>> 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<RpcResult<GetAllMeterConfigStatisticsOutput>> 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<RpcResult<GetAllQueuesStatisticsFromAllPortsOutput>> 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<RpcResult<GetQueueStatisticsFromGivenPortOutput>> 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.
*
*/
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<Node> 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<Short> getTablesFromNode(NodeKey nodeKey){
- InstanceIdentifier<FlowCapableNode> nodesIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class,nodeKey).augmentation(FlowCapableNode.class).toInstance();
-
- FlowCapableNode node = (FlowCapableNode)dps.readOperationalData(nodesIdentifier);
- List<Short> tablesId = new ArrayList<Short>();
- 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<Node> nodeII = (InstanceIdentifier<Node>) 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<NodeKey> 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<NodeKey> 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());
+ }
+ }
+ }
}
+++ /dev/null
-/*
- * 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<InstanceIdentifier<?>, DataObject> change) {
-
- Map<InstanceIdentifier<?>, DataObject> nodeAdditions = change.getCreatedOperationalData();
- for (InstanceIdentifier<? extends DataObject> 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<InstanceIdentifier<?>, DataObject> additions = change.getCreatedConfigurationData();
- for (InstanceIdentifier<? extends DataObject> dataObjectInstance : additions.keySet()) {
- DataObject dataObject = additions.get(dataObjectInstance);
- InstanceIdentifier<Node> 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<NodeConnector> 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<InstanceIdentifier<? extends DataObject>> removals = change.getRemovedConfigurationData();
- for (InstanceIdentifier<? extends DataObject> dataObjectInstance : removals) {
- DataObject dataObject = change.getOriginalConfigurationData().get(dataObjectInstance);
-
- if(dataObject instanceof Flow){
- InstanceIdentifier<Flow> flowII = (InstanceIdentifier<Flow>)dataObjectInstance;
- InstanceIdentifier<?> flowAugmentation =
- InstanceIdentifier.builder(flowII).augmentation(FlowStatisticsData.class).toInstance();
- it.removeOperationalData(flowAugmentation);
- }
- if(dataObject instanceof Meter){
- InstanceIdentifier<Meter> meterII = (InstanceIdentifier<Meter>)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<Group> groupII = (InstanceIdentifier<Group>)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<Queue> queueII = (InstanceIdentifier<Queue>)dataObjectInstance;
-
- InstanceIdentifier<?> nodeConnectorQueueStatisticsDataAugmentation =
- InstanceIdentifier.builder(queueII).augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance();
- it.removeOperationalData(nodeConnectorQueueStatisticsDataAugmentation);
- }
- }
- it.commit();
- }
-}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-base</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.xtend</groupId>
<dependency>
<groupId>equinoxSDK381</groupId>
<artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
- <version>1.7</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.7.1-SNAPSHOT</version>
</dependency>
</dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
package org.opendaylight.controller.netconf.persist.impl;
-import io.netty.channel.EventLoopGroup;
-
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
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;
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;
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<String> latestCapabilities = null;
while (System.nanoTime() < deadlineNanos) {
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<String> getAdditionalHeader() {
- return additionalHeader== null ? Optional.<String>absent() : Optional.of(additionalHeader);
- }
}
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;
private static final Logger logger = LoggerFactory.getLogger(NetconfClientDispatcher.class);
- private final NetconfClientSessionNegotiatorFactory negotatorFactory;
+ private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
private final HashedWheelTimer timer;
- public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, long clientConnectionTimeoutMillis) {
+ public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup,
+ long clientConnectionTimeoutMillis) {
super(bossGroup, workerGroup);
timer = new HashedWheelTimer();
- this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent(), clientConnectionTimeoutMillis);
+ this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer,
+ Optional.<NetconfHelloMessageAdditionalHeader> 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<NetconfClientSession> createClient(InetSocketAddress address,
}
private void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
- new ClientChannelInitializer( negotatorFactory, sessionListener).initialize(ch, promise);
+ new ClientChannelInitializer(negotiatorFactory, sessionListener).initialize(ch, promise);
}
});
}
public Future<Void> 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<NetconfClientSession>() {
}
@Override
- protected void initializeAfterDecoder(SocketChannel ch, Promise<NetconfClientSession> promise) {
- ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(
- new SessionListenerFactory<NetconfClientSessionListener>() {
- @Override
- public NetconfClientSessionListener getSessionListener() {
- return sessionListener;
- }
- }, ch, promise));
+ public void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
+ super.initialize(ch,promise);
+ }
+
+ @Override
+ protected void initializeSessionNegotiator(SocketChannel ch, Promise<NetconfClientSession> promise) {
+ ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
+ negotiatorFactory.getSessionNegotiator(
+ new SessionListenerFactory<NetconfClientSessionListener>() {
+ @Override
+ public NetconfClientSessionListener getSessionListener() {
+ return sessionListener;
+ }
+ }, ch, promise));
}
}
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;
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;
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<NetconfSessionPreferences, NetconfClientSession, NetconfClientSessionListener> {
}
@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()));
}
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;
public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfMessage, NetconfClientSession, NetconfClientSessionListener> {
- private final Optional<String> additionalHeader;
+ private final Optional<NetconfHelloMessageAdditionalHeader> additionalHeader;
private final long connectionTimeoutMillis;
private final Timer timer;
- public NetconfClientSessionNegotiatorFactory(Timer timer, Optional<String> additionalHeader, long connectionTimeoutMillis) {
+ public NetconfClientSessionNegotiatorFactory(Timer timer, Optional<NetconfHelloMessageAdditionalHeader> additionalHeader, long connectionTimeoutMillis) {
this.timer = Preconditions.checkNotNull(timer);
this.additionalHeader = additionalHeader;
this.connectionTimeoutMillis = connectionTimeoutMillis;
Promise<NetconfClientSession> 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);
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;
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.<String>absent(), connectionTimeoutMillis);
+ this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer,
+ Optional.<NetconfHelloMessageAdditionalHeader> 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
@Override
public void initializeChannel(SocketChannel arg0, Promise<NetconfClientSession> arg1) {
- new NetconfSshClientInitializer(authHandler, negotatorFactory, sessionListener).initialize(arg0, arg1);
+ new NetconfSshClientInitializer(authHandler, negotiatorFactory, sessionListener).initialize(arg0, arg1);
}
});
public Future<Void> 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<NetconfClientSession>() {
}
@Override
- protected void initializeAfterDecoder(SocketChannel ch, Promise<NetconfClientSession> promise) {
- ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(new SessionListenerFactory<NetconfClientSessionListener>() {
+ protected void initializeSessionNegotiator(SocketChannel ch,
+ Promise<NetconfClientSession> promise) {
+ ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
+ negotiatorFactory.getSessionNegotiator(new SessionListenerFactory<NetconfClientSessionListener>() {
@Override
public NetconfClientSessionListener getSessionListener() {
return sessionListener;
}
}, ch, promise));
-
}
}
}
public static class ServerChannelInitializer extends AbstractChannelInitializer<NetconfServerSession> {
+ public static final String DESERIALIZER_EX_HANDLER_KEY = "deserializerExHandler";
+
private final NetconfServerSessionNegotiatorFactory negotiatorFactory;
private final NetconfServerSessionListenerFactory listenerFactory;
}
@Override
- protected void initializeAfterDecoder(SocketChannel ch, Promise<NetconfServerSession> 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<NetconfServerSession> promise) {
+ ch.pipeline().addAfter(DESERIALIZER_EX_HANDLER_KEY, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, negotiatorFactory.getSessionNegotiator(listenerFactory, ch, promise));
}
}
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;
private static final Logger logger = LoggerFactory.getLogger(NetconfServerSession.class);
- private final NetconfServerSessionNegotiator.AdditionalHeader header;
+ private final NetconfHelloMessageAdditionalHeader header;
private Date loginTime;
private long inRpcSuccess, inRpcFail, outRpcError;
public NetconfServerSession(NetconfServerSessionListener sessionListener, Channel channel, long sessionId,
- NetconfServerSessionNegotiator.AdditionalHeader header) {
+ NetconfHelloMessageAdditionalHeader header) {
super(sessionListener, channel, sessionId);
this.header = header;
logger.debug("Session {} created", toString());
public static final String ISO_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
+ private static final String dateTimePatternString = DateAndTime.PATTERN_CONSTANTS.get(0);
+ private static final Pattern dateTimePattern = Pattern.compile(dateTimePatternString);
+
@Override
public Session toManagementSession() {
SessionBuilder builder = new SessionBuilder();
Preconditions.checkState(DateAndTime.PATTERN_CONSTANTS.size() == 1);
String formattedDateTime = formatDateTime(loginTime);
- String pattern = DateAndTime.PATTERN_CONSTANTS.get(0);
- Matcher matcher = Pattern.compile(pattern).matcher(formattedDateTime);
- Preconditions.checkState(matcher.matches(), "Formatted datetime %s does not match pattern %s", formattedDateTime, pattern);
+
+ Matcher matcher = dateTimePattern.matcher(formattedDateTime);
+ Preconditions.checkState(matcher.matches(), "Formatted datetime %s does not match pattern %s", formattedDateTime, dateTimePattern);
builder.setLoginTime(new DateAndTime(formattedDateTime));
builder.setInBadRpcs(new ZeroBasedCounter32(inRpcFail));
builder.setInRpcs(new ZeroBasedCounter32(inRpcSuccess));
builder.setOutRpcErrors(new ZeroBasedCounter32(outRpcError));
- builder.setUsername(header.getUsername());
+ builder.setUsername(header.getUserName());
builder.setTransport(getTransportForString(header.getTransport()));
builder.setOutNotifications(new ZeroBasedCounter32(0L));
builder.setKey(new SessionKey(getSessionId()));
Session1Builder builder1 = new Session1Builder();
- builder1.setSessionIdentifier(header.getSessionType());
+ builder1.setSessionIdentifier(header.getSessionIdentifier());
builder.addAugmentation(Session1.class, builder1.build());
return builder.build();
package org.opendaylight.controller.netconf.impl;
-import io.netty.channel.Channel;
-import io.netty.util.Timer;
-import io.netty.util.concurrent.Promise;
-
import java.net.InetSocketAddress;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
-import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil;
import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
+import io.netty.channel.Channel;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Promise;
+
public class NetconfServerSessionNegotiator extends
AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession, NetconfServerSessionListener> {
}
@Override
- protected NetconfServerSession getSession(NetconfServerSessionListener sessionListener, Channel channel, NetconfMessage message) {
- Optional<String> additionalHeader = message.getAdditionalHeader();
+ protected NetconfServerSession getSession(NetconfServerSessionListener sessionListener, Channel channel, NetconfHelloMessage message) {
+ Optional<NetconfHelloMessageAdditionalHeader> 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();
- }
- }
-
-}
+ }
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;
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<NetconfMessage, NetconfServerSession, NetconfServerSessionListener> {
+public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfHelloMessage, NetconfServerSession, NetconfServerSessionListener> {
public static final String SERVER_HELLO_XML_LOCATION = "/server_hello.xml";
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
capabilityElement.setTextContent(capability);
capabilitiesElement.appendChild(capabilityElement);
}
- return new NetconfMessage(helloMessageTemplate);
+ return new NetconfHelloMessage(helloMessageTemplate);
}
private synchronized Document getHelloTemplateClone() {
+++ /dev/null
-/*
- * 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("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+)[^\\]]+\\]");
- private static final Pattern customHeaderPattern = Pattern
- .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+);(?<sessionIdentifier>[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);
- }
-
-}
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());
}
@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());
}
@Test(expected = IllegalArgumentException.class)
public void testParsingNoUsername() throws Exception {
String s = "[10.12.0.102:48528;ssh;;;;;;]";
- AdditionalHeaderUtil.fromString(s);
+ NetconfHelloMessageAdditionalHeader.fromString(s);
}
}
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;
}
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());
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";
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;
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();
}
*/
@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
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;
@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
Element xml = new JaxBSerializer().toXml(model);
}
- private Session getMockSession() {
+ private Session getMockSession(Class<? extends Transport> transportType) {
Session mocked = mock(Session.class);
Session1 mockedSession1 = mock(Session1.class);
doReturn("client").when(mockedSession1).getSessionIdentifier();
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;
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>usermanager</artifactId>
- <version>0.4.2-SNAPSHOT</version>
</dependency>
</dependencies>
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<String> roles = new ArrayList<String>(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);
}
@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;
}
@Override
public void removeUserManagerService() {
- this.um = null;
+ AuthProvider.um = null;
}
@Override
public void addUserManagerService(IUserManager userManagerService) {
- this.um = userManagerService;
+ AuthProvider.um = userManagerService;
}
*/
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;
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;
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) {
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;
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;
logger.error("SocketThread error ",e);
}
}
+ @Override
public ServerSessionCallback acceptSession(final ServerSession session)
{
SimpleServerSessionCallback cb = new SimpleServerSessionCallback()
public Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException
{
return new Runnable(){
+ @Override
public void run()
{
if (subsystem.equals("netconf")){
{
return new Runnable()
{
+ @Override
public void run()
{
//noop
{
return new Runnable()
{
+ @Override
public void run()
{
//noop
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)
{
return AuthenticationResult.FAILURE;
}
+ @Override
public AuthenticationResult authenticateWithPublicKey(ServerConnection sc, String username, String algorithm,
byte[] publickey, byte[] signature)
{
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<String> getUserRoles(String userName) {
@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;
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
- <version>${netconf.netty.version}</version>
</dependency>
<!--dependency>
<groupId>com.siemens.ct.exi</groupId>
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
+import org.opendaylight.controller.netconf.util.handler.NetconfHelloMessageToXMLEncoder;
import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
-import org.opendaylight.controller.netconf.util.handler.NetconfMessageToXMLEncoder;
-import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder;
+import org.opendaylight.controller.netconf.util.handler.NetconfXMLToHelloMessageDecoder;
import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
public abstract class AbstractChannelInitializer<S extends NetconfSession> {
- public void initialize(SocketChannel ch, Promise<S> promise){
- ch.pipeline().addLast("aggregator", new NetconfMessageAggregator(FramingMechanism.EOM));
- ch.pipeline().addLast(new NetconfXMLToMessageDecoder());
- initializeAfterDecoder(ch, promise);
- ch.pipeline().addLast("frameEncoder", FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
- ch.pipeline().addLast(new NetconfMessageToXMLEncoder());
+ public static final String NETCONF_MESSAGE_DECODER = "netconfMessageDecoder";
+ public static final String NETCONF_MESSAGE_AGGREGATOR = "aggregator";
+ public static final String NETCONF_MESSAGE_ENCODER = "netconfMessageEncoder";
+ public static final String NETCONF_MESSAGE_FRAME_ENCODER = "frameEncoder";
+ public static final String NETCONF_SESSION_NEGOTIATOR = "negotiator";
+
+ public void initialize(SocketChannel ch, Promise<S> promise) {
+ ch.pipeline().addLast(NETCONF_MESSAGE_AGGREGATOR, new NetconfMessageAggregator(FramingMechanism.EOM));
+ initializeMessageDecoder(ch);
+ ch.pipeline().addLast(NETCONF_MESSAGE_FRAME_ENCODER, FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
+ initializeMessageEncoder(ch);
+
+ initializeSessionNegotiator(ch, promise);
+ }
+
+ protected void initializeMessageEncoder(SocketChannel ch) {
+ // Special encoding handler for hello message to include additional header if available,
+ // it is thrown away after successful negotiation
+ ch.pipeline().addLast(NETCONF_MESSAGE_ENCODER, new NetconfHelloMessageToXMLEncoder());
+ }
+
+ protected void initializeMessageDecoder(SocketChannel ch) {
+ // Special decoding handler for hello message to parse additional header if available,
+ // it is thrown away after successful negotiation
+ ch.pipeline().addLast(NETCONF_MESSAGE_DECODER, new NetconfXMLToHelloMessageDecoder());
}
- protected abstract void initializeAfterDecoder(SocketChannel ch, Promise<S> promise);
+ /**
+ * Insert session negotiator into the pipeline. It must be inserted after message decoder
+ * identified by {@link AbstractChannelInitializer#NETCONF_MESSAGE_DECODER}, (or any other custom decoder processor)
+ */
+ protected abstract void initializeSessionNegotiator(SocketChannel ch, Promise<S> promise);
}
package org.opendaylight.controller.netconf.util;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.ssl.SslHandler;
-import io.netty.util.Timeout;
-import io.netty.util.Timer;
-import io.netty.util.TimerTask;
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.GenericFutureListener;
-import io.netty.util.concurrent.Promise;
-
import java.util.concurrent.TimeUnit;
import org.opendaylight.controller.netconf.api.AbstractNetconfSession;
import org.opendaylight.controller.netconf.api.NetconfSessionListener;
import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
import org.opendaylight.controller.netconf.util.handler.NetconfMessageChunkDecoder;
+import org.opendaylight.controller.netconf.util.handler.NetconfMessageToXMLEncoder;
+import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder;
import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.protocol.framework.AbstractSessionNegotiator;
import org.slf4j.Logger;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.ssl.SslHandler;
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GenericFutureListener;
+import io.netty.util.concurrent.Promise;
+
public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionPreferences, S extends AbstractNetconfSession<S, L>, L extends NetconfSessionListener<S>>
-extends AbstractSessionNegotiator<NetconfMessage, S> {
+extends AbstractSessionNegotiator<NetconfHelloMessage, S> {
private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSessionNegotiator.class);
public static final String NAME_OF_EXCEPTION_HANDLER = "lastExceptionHandler";
+ public static final String CHUNK_DECODER_CHANNEL_HANDLER_KEY = "chunkDecoder";
protected final P sessionPreferences;
}
@Override
- protected void handleMessage(NetconfMessage netconfMessage) {
+ protected void handleMessage(NetconfHelloMessage netconfMessage) {
final Document doc = netconfMessage.getDocument();
- if (isHelloMessage(doc)) {
- if (containsBase11Capability(doc)
- && containsBase11Capability(sessionPreferences.getHelloMessage().getDocument())) {
- channel.pipeline().replace("frameEncoder", "frameEncoder",
- FramingMechanismHandlerFactory.createHandler(FramingMechanism.CHUNK));
- channel.pipeline().replace("aggregator", "aggregator",
- new NetconfMessageAggregator(FramingMechanism.CHUNK));
- channel.pipeline().addAfter("aggregator", "chunkDecoder", new NetconfMessageChunkDecoder());
+ // Only Hello message should arrive during negotiation
+ if (netconfMessage instanceof NetconfHelloMessage) {
+
+ replaceHelloMessageHandlers();
+
+ if (shouldUseChunkFraming(doc)) {
+ insertChunkFramingToPipeline();
}
+
changeState(State.ESTABLISHED);
- S session = getSession(sessionListener, channel, netconfMessage);
+ S session = getSession(sessionListener, channel, (NetconfHelloMessage)netconfMessage);
+
negotiationSuccessful(session);
} else {
final IllegalStateException cause = new IllegalStateException(
}
}
- protected abstract S getSession(L sessionListener, Channel channel, NetconfMessage message);
+ /**
+ * Insert chunk framing handlers into the pipeline
+ */
+ private void insertChunkFramingToPipeline() {
+ replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_FRAME_ENCODER,
+ FramingMechanismHandlerFactory.createHandler(FramingMechanism.CHUNK));
+ replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_AGGREGATOR,
+ new NetconfMessageAggregator(FramingMechanism.CHUNK));
+ channel.pipeline().addAfter(AbstractChannelInitializer.NETCONF_MESSAGE_AGGREGATOR,
+ CHUNK_DECODER_CHANNEL_HANDLER_KEY, new NetconfMessageChunkDecoder());
+ }
+
+ private boolean shouldUseChunkFraming(Document doc) {
+ return containsBase11Capability(doc)
+ && containsBase11Capability(sessionPreferences.getHelloMessage().getDocument());
+ }
- private boolean isHelloMessage(Document doc) {
- try {
- XmlElement.fromDomElementWithExpected(doc.getDocumentElement(), "hello",
- XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+ /**
+ * Remove special handlers for hello message. Insert regular netconf xml message (en|de)coders.
+ */
+ private void replaceHelloMessageHandlers() {
+ replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, new NetconfXMLToMessageDecoder());
+ replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_ENCODER, new NetconfMessageToXMLEncoder());
+ }
- } catch (IllegalArgumentException | IllegalStateException e) {
- return false;
- }
- return true;
+ private static ChannelHandler replaceChannelHandler(Channel channel, String handlerKey, ChannelHandler decoder) {
+ return channel.pipeline().replace(handlerKey, handlerKey, decoder);
}
+ protected abstract S getSession(L sessionListener, Channel channel, NetconfHelloMessage message);
+
private synchronized void changeState(final State newState) {
logger.debug("Changing state from : {} to : {}", state, newState);
Preconditions.checkState(isStateChangePermitted(state, newState), "Cannot change state from %s to %s", state,
--- /dev/null
+/*
+ * 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.netconf.util.handler;
+
+import java.nio.ByteBuffer;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * Customized NetconfMessageToXMLEncoder that serializes additional header with
+ * session metadata along with
+ * {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage}
+ * . Used by netconf clients to send information about the user, ip address,
+ * protocol etc.
+ * <p/>
+ * Hello message with header example:
+ * <p/>
+ *
+ * <pre>
+ * {@code
+ * [tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]
+ * <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ * <capabilities>
+ * <capability>urn:ietf:params:netconf:base:1.0</capability>
+ * </capabilities>
+ * </hello>
+ * }
+ * </pre>
+ */
+public final class NetconfHelloMessageToXMLEncoder extends NetconfMessageToXMLEncoder {
+
+ @Override
+ protected ByteBuffer encodeMessage(NetconfMessage msg) {
+ Preconditions.checkState(msg instanceof NetconfHelloMessage, "Netconf message of type %s expected, was %s",
+ NetconfHelloMessage.class, msg.getClass());
+ Optional<NetconfHelloMessageAdditionalHeader> headerOptional = ((NetconfHelloMessage) msg)
+ .getAdditionalHeader();
+
+ // If additional header present, serialize it along with netconf hello
+ // message
+ if (headerOptional.isPresent()) {
+ byte[] bytesFromHeader = headerOptional.get().toFormattedString().getBytes(Charsets.UTF_8);
+ byte[] bytesFromMessage = xmlToString(msg.getDocument()).getBytes(Charsets.UTF_8);
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(bytesFromHeader.length + bytesFromMessage.length)
+ .put(bytesFromHeader).put(bytesFromMessage);
+ byteBuffer.flip();
+ return byteBuffer;
+ }
+
+ return super.encodeMessage(msg);
+ }
+}
import com.google.common.base.Charsets;
import com.google.common.base.Optional;
-public final class NetconfMessageToXMLEncoder extends MessageToByteEncoder<NetconfMessage> {
+public class NetconfMessageToXMLEncoder extends MessageToByteEncoder<NetconfMessage> {
private static final Logger LOG = LoggerFactory.getLogger(NetconfMessageToXMLEncoder.class);
private final Optional<String> clientId;
msg.getDocument().appendChild(comment);
}
- final ByteBuffer msgBytes;
- if(msg.getAdditionalHeader().isPresent()) {
- final String header = msg.getAdditionalHeader().get();
- LOG.trace("Header of netconf message parsed \n{}", header);
- // FIXME: this can be written in pieces
- msgBytes = Charsets.UTF_8.encode(header + xmlToString(msg.getDocument()));
- } else {
- msgBytes = Charsets.UTF_8.encode(xmlToString(msg.getDocument()));
- }
+ final ByteBuffer msgBytes = encodeMessage(msg);
LOG.trace("Putting message \n{}", xmlToString(msg.getDocument()));
out.writeBytes(msgBytes);
}
- private String xmlToString(Document doc) {
+ protected ByteBuffer encodeMessage(NetconfMessage msg) {
+ return Charsets.UTF_8.encode(xmlToString(msg.getDocument()));
+ }
+
+ protected String xmlToString(Document doc) {
return XmlUtil.toString(doc, false);
}
}
--- /dev/null
+/*
+ * 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.netconf.util.handler;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.w3c.dom.Document;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Customized NetconfXMLToMessageDecoder that reads additional header with
+ * session metadata from
+ * {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage}
+ * . Used by netconf server to retrieve information about session metadata.
+ */
+public class NetconfXMLToHelloMessageDecoder extends NetconfXMLToMessageDecoder {
+
+ private static final List<byte[]> POSSIBLE_ENDS = ImmutableList.of(
+ new byte[] { ']', '\n' },
+ new byte[] { ']', '\r', '\n' });
+ private static final List<byte[]> POSSIBLE_STARTS = ImmutableList.of(
+ new byte[] { '[' },
+ new byte[] { '\r', '\n', '[' },
+ new byte[] { '\n', '[' });
+
+ private String additionalHeaderCache;
+
+ @Override
+ protected byte[] preprocessMessageBytes(byte[] bytes) {
+ // Extract bytes containing header with additional metadata
+
+ if (startsWithAdditionalHeader(bytes)) {
+ // Auth information containing username, ip address... extracted for monitoring
+ int endOfAuthHeader = getAdditionalHeaderEndIndex(bytes);
+ if (endOfAuthHeader > -1) {
+ byte[] additionalHeaderBytes = Arrays.copyOfRange(bytes, 0, endOfAuthHeader + 2);
+ additionalHeaderCache = additionalHeaderToString(additionalHeaderBytes);
+ bytes = Arrays.copyOfRange(bytes, endOfAuthHeader + 2, bytes.length);
+ }
+ }
+
+ return bytes;
+ }
+
+ @Override
+ protected void cleanUpAfterDecode() {
+ additionalHeaderCache = null;
+ }
+
+ @Override
+ protected NetconfMessage buildNetconfMessage(Document doc) {
+ return new NetconfHelloMessage(doc, additionalHeaderCache == null ? null
+ : NetconfHelloMessageAdditionalHeader.fromString(additionalHeaderCache));
+ }
+
+ private int getAdditionalHeaderEndIndex(byte[] bytes) {
+ for (byte[] possibleEnd : POSSIBLE_ENDS) {
+ int idx = findByteSequence(bytes, possibleEnd);
+
+ if (idx != -1) {
+ return idx;
+ }
+ }
+
+ return -1;
+ }
+
+ private static int findByteSequence(final byte[] bytes, final byte[] sequence) {
+ if (bytes.length < sequence.length) {
+ throw new IllegalArgumentException("Sequence to be found is longer than the given byte array.");
+ }
+ if (bytes.length == sequence.length) {
+ if (Arrays.equals(bytes, sequence)) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+ int j = 0;
+ for (int i = 0; i < bytes.length; i++) {
+ if (bytes[i] == sequence[j]) {
+ j++;
+ if (j == sequence.length) {
+ return i - j + 1;
+ }
+ } else {
+ j = 0;
+ }
+ }
+ return -1;
+ }
+
+ private boolean startsWithAdditionalHeader(byte[] bytes) {
+ for (byte[] possibleStart : POSSIBLE_STARTS) {
+ int i = 0;
+ for (byte b : possibleStart) {
+ if(bytes[i++] != b)
+ break;
+
+ if(i == possibleStart.length)
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private String additionalHeaderToString(byte[] bytes) {
+ return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
+ }
+
+}
*/
package org.opendaylight.controller.netconf.util.handler;
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufUtil;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.ByteToMessageDecoder;
-
import java.io.ByteArrayInputStream;
-import java.io.IOException;
import java.nio.ByteBuffer;
-import java.util.Arrays;
import java.util.List;
import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableList;
-public final class NetconfXMLToMessageDecoder extends ByteToMessageDecoder {
- private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToMessageDecoder.class);
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
- private static final List<byte[]> POSSIBLE_ENDS = ImmutableList.of(
- new byte[] { ']', '\n' },
- new byte[] { ']', '\r', '\n' });
- private static final List<byte[]> POSSIBLE_STARTS = ImmutableList.of(
- new byte[] { '[' },
- new byte[] { '\r', '\n', '[' },
- new byte[] { '\n', '[' });
+public class NetconfXMLToMessageDecoder extends ByteToMessageDecoder {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToMessageDecoder.class);
@Override
@VisibleForTesting
logMessage(bytes);
- String additionalHeader = null;
-
- // FIXME: this has to be moved into the negotiator and explained as to what the heck
- // is going on. This is definitely not specified in NETCONF and has no place here. It
- // requires reading all data and incurs inefficiency by being unable to pipe the ByteBuf
- // directly into the XML decoder.
- if (startsWithAdditionalHeader(bytes)) {
- // Auth information containing username, ip address... extracted for monitoring
- int endOfAuthHeader = getAdditionalHeaderEndIndex(bytes);
- if (endOfAuthHeader > -1) {
- byte[] additionalHeaderBytes = Arrays.copyOfRange(bytes, 0, endOfAuthHeader + 2);
- additionalHeader = additionalHeaderToString(additionalHeaderBytes);
- bytes = Arrays.copyOfRange(bytes, endOfAuthHeader + 2, bytes.length);
- }
- }
+ bytes = preprocessMessageBytes(bytes);
NetconfMessage message;
try {
Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes));
- message = new NetconfMessage(doc, additionalHeader);
- } catch (final SAXException | IOException | IllegalStateException e) {
+ message = buildNetconfMessage(doc);
+ } catch (Exception e) {
throw new NetconfDeserializerException("Could not parse message from " + new String(bytes), e);
}
out.add(message);
} finally {
in.discardReadBytes();
+ cleanUpAfterDecode();
}
}
- private int getAdditionalHeaderEndIndex(byte[] bytes) {
- for (byte[] possibleEnd : POSSIBLE_ENDS) {
- int idx = findByteSequence(bytes, possibleEnd);
-
- if (idx != -1) {
- return idx;
- }
- }
+ protected void cleanUpAfterDecode() {}
- return -1;
+ protected NetconfMessage buildNetconfMessage(Document doc) {
+ return new NetconfMessage(doc);
}
- private static int findByteSequence(final byte[] bytes, final byte[] sequence) {
- if (bytes.length < sequence.length) {
- throw new IllegalArgumentException("Sequence to be found is longer than the given byte array.");
- }
- if (bytes.length == sequence.length) {
- if (Arrays.equals(bytes, sequence)) {
- return 0;
- } else {
- return -1;
- }
- }
- int j = 0;
- for (int i = 0; i < bytes.length; i++) {
- if (bytes[i] == sequence[j]) {
- j++;
- if (j == sequence.length) {
- return i - j + 1;
- }
- } else {
- j = 0;
- }
- }
- return -1;
+ protected byte[] preprocessMessageBytes(byte[] bytes) {
+ return bytes;
}
- private boolean startsWithAdditionalHeader(byte[] bytes) {
- for (byte[] possibleStart : POSSIBLE_STARTS) {
- int i = 0;
- for (byte b : possibleStart) {
- if(bytes[i] != b)
- break;
-
- return true;
- }
- }
-
- return false;
- };
-
private void logMessage(byte[] bytes) {
String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
LOG.debug("Parsing message \n{}", s);
}
- private String additionalHeaderToString(byte[] bytes) {
- return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
- }
-
}
--- /dev/null
+/*
+ * 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.util.messages;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+
+import com.google.common.base.Optional;
+
+/**
+ * NetconfMessage that can carry additional header with session metadata. See {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader}
+ */
+public final class NetconfHelloMessage extends NetconfMessage {
+
+ public static final String HELLO_TAG = "hello";
+
+ private final NetconfHelloMessageAdditionalHeader additionalHeader;
+
+ public NetconfHelloMessage(Document doc, NetconfHelloMessageAdditionalHeader additionalHeader) {
+ super(doc);
+ checkHelloMessage(doc);
+ this.additionalHeader = additionalHeader;
+ }
+
+ public NetconfHelloMessage(Document doc) {
+ this(doc, null);
+ }
+
+ public Optional<NetconfHelloMessageAdditionalHeader> getAdditionalHeader() {
+ return additionalHeader== null ? Optional.<NetconfHelloMessageAdditionalHeader>absent() : Optional.of(additionalHeader);
+ }
+
+ private static void checkHelloMessage(Document doc) {
+ try {
+ XmlElement.fromDomElementWithExpected(doc.getDocumentElement(), HELLO_TAG,
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ throw new IllegalArgumentException(String.format(
+ "Hello message invalid format, should contain %s tag from namespace %s, but is: %s", HELLO_TAG,
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, XmlUtil.toString(doc)), e);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.util.messages;
+
+import com.google.common.base.Preconditions;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Additional header can be used with hello message to carry information about
+ * session's connection. Provided information can be reported via netconf
+ * monitoring.
+ * <pre>
+ * It has pattern "[username; host-address:port; transport; session-identifier;]"
+ * username - name of account on a remote
+ * host-address - client's IP address
+ * port - port number
+ * transport - tcp, ssh
+ * session-identifier - persister, client
+ * Session-identifier is optional, others mandatory.
+ * </pre>
+ * This header is inserted in front of a netconf hello message followed by a newline.
+ */
+public class NetconfHelloMessageAdditionalHeader {
+
+ private static final String SC = ";";
+
+ private final String userName;
+ private final String hostAddress;
+ private final String port;
+ private final String transport;
+ private final String sessionIdentifier;
+
+ public NetconfHelloMessageAdditionalHeader(String userName, String hostAddress, String port, String transport, String sessionIdentifier) {
+ this.userName = userName;
+ this.hostAddress = hostAddress;
+ this.port = port;
+ this.transport = transport;
+ this.sessionIdentifier = sessionIdentifier;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public String getAddress() {
+ return hostAddress;
+ }
+
+ public String getPort() {
+ return port;
+ }
+
+ public String getTransport() {
+ return transport;
+ }
+
+ public String getSessionIdentifier() {
+ return sessionIdentifier;
+ }
+
+ /**
+ * Format additional header into a string suitable as a prefix for netconf hello message
+ */
+ public String toFormattedString() {
+ Preconditions.checkNotNull(userName);
+ Preconditions.checkNotNull(hostAddress);
+ Preconditions.checkNotNull(port);
+ Preconditions.checkNotNull(transport);
+ Preconditions.checkNotNull(sessionIdentifier);
+ return "[" + userName + SC + hostAddress + ":" + port + SC + transport + SC + sessionIdentifier + SC + "]"
+ + System.lineSeparator();
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("NetconfHelloMessageAdditionalHeader{");
+ sb.append("userName='").append(userName).append('\'');
+ sb.append(", hostAddress='").append(hostAddress).append('\'');
+ sb.append(", port='").append(port).append('\'');
+ sb.append(", transport='").append(transport).append('\'');
+ sb.append(", sessionIdentifier='").append(sessionIdentifier).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+
+ // TODO IPv6
+ private static final Pattern pattern = Pattern
+ .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+)[^\\]]+\\]");
+ private static final Pattern customHeaderPattern = Pattern
+ .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+);(?<sessionIdentifier>[a-z]+)[^\\]]+\\]");
+
+ /**
+ * Parse additional header from a formatted string
+ */
+ public static NetconfHelloMessageAdditionalHeader 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 port = matcher.group("port");
+ String transport = matcher.group("transport");
+ String sessionIdentifier = "client";
+ if (matcher2.matches()) {
+ sessionIdentifier = matcher2.group("sessionIdentifier");
+ }
+ return new NetconfHelloMessageAdditionalHeader(username, address, port, transport, sessionIdentifier);
+ }
+
+}
+++ /dev/null
-/*
- * 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.util.messages;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-
-/**
- * Additional header can be used with hello message to carry information about
- * session's connection. Provided information can be reported via netconf
- * monitoring.
- * <pre>
- * It has pattern "[username; host-address:port; transport; session-identifier;]"
- * username - name of account on a remote
- * host-address - client's IP address
- * port - port number
- * transport - tcp, ssh
- * session-identifier - persister, client
- * Session-identifier is optional, others mandatory.
- * </pre>
- */
-public class NetconfMessageAdditionalHeader {
-
- private static final String SC = ";";
-
- public static String toString(String userName, String hostAddress, String port, String transport,
- Optional<String> sessionIdentifier) {
- Preconditions.checkNotNull(userName);
- Preconditions.checkNotNull(hostAddress);
- Preconditions.checkNotNull(port);
- Preconditions.checkNotNull(transport);
- String identifier = sessionIdentifier.isPresent() ? sessionIdentifier.get() : "";
- return "[" + userName + SC + hostAddress + ":" + port + SC + transport + SC + identifier + SC + "]"
- + System.lineSeparator();
- }
-}
import java.util.List;
import org.junit.Test;
+import org.opendaylight.controller.netconf.util.handler.NetconfXMLToHelloMessageDecoder;
import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder;
import com.google.common.io.Files;
public class NetconfMessageFactoryTest {
@Test
public void testAuth() throws Exception {
- NetconfXMLToMessageDecoder parser = new NetconfXMLToMessageDecoder();
+ NetconfXMLToMessageDecoder parser = new NetconfXMLToHelloMessageDecoder();
File authHelloFile = new File(getClass().getResource("/netconfMessages/client_hello_with_auth.xml").getFile());
final List<Object> out = new ArrayList<>();
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
</plugin>
<plugin>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
- <version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.7.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
- <version>${enunciate.version}</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
- BroadcastMode mode = BroadcastMode.BROADCAST_TO_NONINTERNAL;
+ BroadcastMode mode = BroadcastMode.DISABLED;
@Override
public PacketResult receiveDataPacket(RawPacket inPkt) {
try {
boolean retStatus;
if(oldLatch != null) {
- retStatus = oldLatch.await(this.latchTimeout, TimeUnit.SECONDS);
+ retStatus = oldLatch.await(StatisticsManager.latchTimeout, TimeUnit.SECONDS);
} else {
- retStatus = newLatch.await(this.latchTimeout, TimeUnit.SECONDS);
+ retStatus = newLatch.await(StatisticsManager.latchTimeout, TimeUnit.SECONDS);
}
// log the return code as it will give us, if
// the latch timed out.
}
}
- boolean proactiveForwarding = false;
+ boolean forwardingModeChanged = false;
+
// copy node properties from config
if (nodeConfigList != null) {
String nodeId = node.toString();
propMap.putAll(nodeProperties);
if (nodeProperties.get(ForwardingMode.name) != null) {
ForwardingMode mode = (ForwardingMode) nodeProperties.get(ForwardingMode.name);
- proactiveForwarding = mode.isProactive();
+ forwardingModeChanged = mode.isProactive();
}
}
}
Property defaultMode = new ForwardingMode(ForwardingMode.REACTIVE_FORWARDING);
propMap.put(ForwardingMode.name, defaultMode);
}
- boolean result = false;
- if (propMapCurr == null) {
- if (nodeProps.putIfAbsent(node, propMap) == null) {
- result = true;
- }
+
+ boolean propsAdded = false;
+ // Attempt initial add
+ if (nodeProps.putIfAbsent(node, propMap) == null) {
+ propsAdded = true;
+
+ /* Notify listeners only for initial node addition
+ * to avoid expensive tasks triggered by redundant notifications
+ */
+ notifyNode(node, UpdateType.ADDED, propMap);
} else {
- result = nodeProps.replace(node, propMapCurr, propMap);
+
+ propsAdded = nodeProps.replace(node, propMapCurr, propMap);
+
+ // check whether forwarding mode changed
+ if (propMapCurr.get(ForwardingMode.name) != null) {
+ ForwardingMode mode = (ForwardingMode) propMapCurr.get(ForwardingMode.name);
+ forwardingModeChanged ^= mode.isProactive();
+ }
}
- if (!result) {
- log.debug("Cluster conflict: Conflict while adding the node properties. Node: {} Properties: {}",
- node.getID(), props);
+ if (!propsAdded) {
+ log.debug("Cluster conflict while adding node {}. Overwriting with latest props: {}", node.getID(), props);
addNodeProps(node, propMap);
}
- // check if span ports are configed
+ // check if span ports are configured
addSpanPorts(node);
-
- // notify node listeners
- notifyNode(node, UpdateType.ADDED, propMap);
-
// notify proactive mode forwarding
- if (proactiveForwarding) {
+ if (forwardingModeChanged) {
notifyModeChange(node, true);
}
}
if (nodeProps == null) {
return;
}
- nodeProps.remove(node);
+
+ if (nodeProps.remove(node) == null) {
+ log.debug("Received redundant node REMOVED udate for {}. Skipping..", node);
+ return;
+ }
+
nodeConnectorNames.remove(node);
Set<NodeConnector> removeNodeConnectorSet = new HashSet<NodeConnector>();
for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
switch (type) {
case ADDED:
+ // Skip redundant ADDED update (e.g. cluster switch-over)
+ if (nodeConnectorProps.containsKey(nodeConnector)) {
+ log.debug("Redundant nodeconnector ADDED for {}, props {} for container {}",
+ nodeConnector, props, containerName);
+ update = false;
+ }
+
if (props != null) {
for (Property prop : props) {
addNodeConnectorProp(nodeConnector, prop);
addNodeConnectorProp(nodeConnector, null);
}
+
addSpanPort(nodeConnector);
break;
case CHANGED:
// only add if span is configured on this nodeConnector
for (SpanConfig conf : getSpanConfigList(nodeConnector.getNode())) {
if (conf.getPortArrayList().contains(nodeConnector)) {
- List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
- ncLists.add(nodeConnector);
- addSpanPorts(nodeConnector.getNode(), ncLists);
+ List<NodeConnector> ncList = new ArrayList<NodeConnector>();
+ ncList.add(nodeConnector);
+ addSpanPorts(nodeConnector.getNode(), ncList);
return;
}
}
public Set<Switch> getConfiguredNotConnectedSwitches() {
Set<Switch> configuredNotConnectedSwitches = new HashSet<Switch>();
if (this.inventoryService == null) {
- log.trace("inventory service not avaiable");
+ log.trace("inventory service not available");
return configuredNotConnectedSwitches;
}
var editButton = one.lib.dashlet.button.single("Edit Flow", one.f.flows.id.dashlet.edit, "btn-primary", "btn-mini");
var $editButton = one.lib.dashlet.button.button(editButton);
$editButton.click(function() {
- var $modal = one.f.flows.modal.initialize(true);
+ var install = flow['flow']['installInHw'];
+ var $modal = one.f.flows.modal.initialize(true,install);
$modal.modal().on('shown',function(){
var $port = $('#'+one.f.flows.id.modal.form.port);
$('#'+one.f.flows.id.modal.form.nodes).trigger("change");
return $p;
}
},
- initialize : function(edit) {
+ initialize : function(edit,install) {
var h3;
if(edit) {
h3 = "Edit Flow Entry";
if (edit) {
// bind edit flow button
$('#'+one.f.flows.id.modal.edit, $modal).click(function() {
- one.f.flows.modal.save($modal, 'true', true);
+ one.f.flows.modal.save($modal, install, true);
});
} else {
// bind add flow button