<configuration>
<instructions>
<Import-Package>
+ org.opendaylight.controller.configuration,
org.opendaylight.controller.containermanager,
org.opendaylight.controller.sal.authorization,
org.opendaylight.controller.sal.utils,
</build>
<dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>configuration</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
+import org.opendaylight.controller.configuration.ConfigurationObject;
import org.opendaylight.controller.containermanager.IContainerAuthorization;
import org.opendaylight.controller.sal.authorization.AppRoleLevel;
import org.opendaylight.controller.sal.authorization.IResourceAuthorization;
*/
public abstract class Authorization<T> implements IResourceAuthorization {
private static final Logger logger = LoggerFactory.getLogger(Authorization.class);
- private static final String namesRegex = "^[a-zA-Z0-9]+[{\\.|\\_|\\-}[a-zA-Z0-9]]*$";
+ private static final String namesRegex = ConfigurationObject.getRegularExpression();
/*
* The configured resource groups
*/
* 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;
<prerequisites>
<maven>3.0</maven>
</prerequisites>
- <groupId>org.opendaylight.controller</groupId>
<artifactId>commons.opendaylight</artifactId>
<version>1.4.2-SNAPSHOT</version>
<packaging>pom</packaging>
<testvm.argLine>-Xmx1024m -XX:MaxPermSize=256m</testvm.argLine>
<guava.version>14.0.1</guava.version>
<osgi.core.version>5.0.0</osgi.core.version>
- <ietf-inet-types.version>2010.09.24.3</ietf-inet-types.version>
- <ietf-yang-types.version>2010.09.24.3</ietf-yang-types.version>
- <ietf-topology.version>2013.10.21.1</ietf-topology.version>
- <opendaylight-l2-types.version>2013.08.27.3</opendaylight-l2-types.version>
- <yang-ext.version>2013.09.07.3</yang-ext.version>
+ <ietf-inet-types.version>2010.09.24.4-SNAPSHOT</ietf-inet-types.version>
+ <ietf-yang-types.version>2010.09.24.4-SNAPSHOT</ietf-yang-types.version>
+ <ietf-topology.version>2013.10.21.2-SNAPSHOT</ietf-topology.version>
+ <opendaylight-l2-types.version>2013.08.27.4-SNAPSHOT</opendaylight-l2-types.version>
+ <yang-ext.version>2013.09.07.4-SNAPSHOT</yang-ext.version>
<javassist.version>3.17.1-GA</javassist.version>
<releaseplugin.version>2.3.2</releaseplugin.version>
<commons.lang.version>3.1</commons.lang.version>
<networkconfig.bridgedomain.northbound.version>0.0.3-SNAPSHOT</networkconfig.bridgedomain.northbound.version>
<commons.httpclient.version>0.1.2-SNAPSHOT</commons.httpclient.version>
<concepts.version>0.5.2-SNAPSHOT</concepts.version>
- <protocol-framework.version>0.4.1-SNAPSHOT</protocol-framework.version>
+ <protocol-framework.version>0.5.0-SNAPSHOT</protocol-framework.version>
<netty.version>4.0.10.Final</netty.version>
<commons.io.version>2.4</commons.io.version>
<bundlescanner.version>0.4.2-SNAPSHOT</bundlescanner.version>
<artifactId>netty-common</artifactId>
<version>${netty.version}</version>
</dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-codec-http</artifactId>
+ <version>${netty.version}</version>
+ </dependency>
<!-- yangtools dependencies -->
<dependency>
<artifactId>yang-model-api</artifactId>
<version>${yangtools.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-util</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
+
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>hosttracker</artifactId>
<artifactId>clustering.stub</artifactId>
<version>${clustering.stub.version}</version>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>configuration</artifactId>
- <version>${controller.version}</version>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>configuration.implementation</artifactId>
<artifactId>netty-timer-config</artifactId>
<version>${config.version}</version>
</dependency>
-
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>configuration</artifactId>
</scm>
<artifactId>protocol-framework</artifactId>
- <version>0.4.1-SNAPSHOT</version>
+ <version>0.5.0-SNAPSHOT</version>
<description>Common protocol framework</description>
<packaging>bundle</packaging>
<name>${project.artifactId}</name>
+++ /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.protocol.framework;
-
-/**
- * Used when something occurs during parsing bytes to java objects.
- *
- * @deprecated This exception no longer carries any special meaning. Users
- * are advised to stop using it and define their own replacement.
- */
-@Deprecated
-public class DeserializerException extends Exception {
-
- private static final long serialVersionUID = -2247000673438452870L;
-
- /**
- * Creates a deserializer exception.
- * @param err string
- */
- public DeserializerException(final String err) {
- super(err);
- }
-
- /**
- * Creates a deserializer exception.
- * @param err string
- * @param e underlying exception
- */
- public DeserializerException(final String err, final Throwable e) {
- super(err, 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.protocol.framework;
-
-/**
- * Documented exception occurrs when an error is thrown that is documented
- * in any RFC or draft for the specific protocol.
- *
- * @deprecated This exception no longer carries any special meaning. Users
- * are advised to stop using it and define their own replacement.
- */
-@Deprecated
-public class DocumentedException extends Exception {
-
- private static final long serialVersionUID = -3727963789710833704L;
-
- /**
- * Creates a documented exception
- * @param message string
- */
- public DocumentedException(final String message) {
- super(message);
- }
-
- /**
- * Creates a documented exception
- * @param err string
- * @param cause the cause (which is saved for later retrieval by the
- * Throwable.getCause() method). (A null value is permitted, and indicates
- * that the cause is nonexistent or unknown.)
- */
- public DocumentedException(final String err, final Exception cause) {
- super(err, cause);
- }
-}
+++ /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.protocol.framework;
-
-import io.netty.channel.ChannelHandler;
-
-import com.google.common.base.Preconditions;
-
-/**
- * @deprecated This is an adaptor class for turning ProtocolMessageFactory into
- * Netty encoder/decoder. Use Netty-provided classes directly, by subclassing
- * {@link io.netty.handler.codec.ByteToMessageDecoder} or similar instead.
- */
-@Deprecated
-public class ProtocolHandlerFactory<T> {
- private final ProtocolMessageEncoder<T> encoder;
- protected final ProtocolMessageFactory<T> msgFactory;
-
- public ProtocolHandlerFactory(final ProtocolMessageFactory<T> msgFactory) {
- this.msgFactory = Preconditions.checkNotNull(msgFactory);
- this.encoder = new ProtocolMessageEncoder<T>(msgFactory);
- }
-
- public ChannelHandler[] getEncoders() {
- return new ChannelHandler[] { this.encoder };
- }
-
- public ChannelHandler[] getDecoders() {
- return new ChannelHandler[] { new ProtocolMessageDecoder<T>(this.msgFactory) };
- }
-}
+++ /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.protocol.framework;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufUtil;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.ByteToMessageDecoder;
-
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-
-/**
- * @deprecated This is an adaptor class for turning ProtocolMessageFactory into Netty decoder. Use Netty-provided
- * classes directly, by subclassing {@link io.netty.handler.codec.ByteToMessageDecoder} or similar instead.
- */
-@Deprecated
-public final class ProtocolMessageDecoder<T> extends ByteToMessageDecoder {
-
- private static final Logger LOG = LoggerFactory.getLogger(ProtocolMessageDecoder.class);
-
- private final ProtocolMessageFactory<T> factory;
-
- public ProtocolMessageDecoder(final ProtocolMessageFactory<T> factory) {
- this.factory = Preconditions.checkNotNull(factory);
- }
-
- @Override
- protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final List<Object> out) throws Exception {
- if (in.readableBytes() == 0) {
- LOG.debug("No more content in incoming buffer.");
- return;
- }
- in.markReaderIndex();
- try {
- LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in));
- final byte[] bytes = new byte[in.readableBytes()];
- in.readBytes(bytes);
- out.add(this.factory.parse(bytes));
- } catch (DeserializerException | DocumentedException e) {
- LOG.debug("Failed to decode protocol message", e);
- this.exceptionCaught(ctx, e);
- }
- in.discardReadBytes();
- }
-}
+++ /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.protocol.framework;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.ChannelHandler.Sharable;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.MessageToByteEncoder;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * @deprecated This is an adaptor class for turning ProtocolMessageFactory into Netty encoder. Use Netty-provided
- * classes directly, by subclassing {@link io.netty.handler.codec.MessageToByteDecoder} or similar instead.
- */
-@Deprecated
-@Sharable
-public final class ProtocolMessageEncoder<T> extends MessageToByteEncoder<Object> {
-
- private static final Logger LOG = LoggerFactory.getLogger(ProtocolMessageEncoder.class);
-
- private final ProtocolMessageFactory<T> factory;
-
- public ProtocolMessageEncoder(final ProtocolMessageFactory<T> factory) {
- this.factory = factory;
- }
-
- @Override
- protected void encode(final ChannelHandlerContext ctx, final Object msg, final ByteBuf out) throws Exception {
- LOG.debug("Sent to encode : {}", msg);
- final byte[] bytes = this.factory.put((T) msg);
- out.writeBytes(bytes);
- }
-}
+++ /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.protocol.framework;
-
-
-/**
- * Interface for factory for parsing and serializing protocol specific messages. Needs to be implemented by a protocol
- * specific message factory. The methods put/parse should delegate parsing to specific message parsers, e.g.
- * OpenMessageParser etc.
- *
- * @param <T> type of messages created by this factory
- *
- * @deprecated Interact with Netty 4.0 directly, by subclassing {@link io.netty.handler.codec.ByteToMessageCodec} or
- * similar.
- */
-@Deprecated
-public interface ProtocolMessageFactory<T> {
-
- /**
- * Parses message from byte array. Requires specific protocol message header object to parse the header.
- *
- * @param bytes byte array from which the message will be parsed
- * @return List of specific protocol messages
- * @throws DeserializerException if some parsing error occurs
- * @throws DocumentedException if some documented error occurs
- */
- T parse(byte[] bytes) throws DeserializerException, DocumentedException;
-
- /**
- * Serializes protocol specific message to byte array.
- *
- * @param msg message to be serialized.
- * @return byte array resulting message
- */
- byte[] put(T msg);
-}
+++ /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.protocol.framework;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-
-@Deprecated
-public class ComplementaryTest {
-
- @Test
- public void testExceptions() {
- final DeserializerException de = new DeserializerException("some error");
- final DocumentedException ee = new DocumentedException("some error");
-
- assertEquals(de.getMessage(), ee.getMessage());
- }
-}
import org.opendaylight.yangtools.concepts.Identifier;
public class TransactionIdentifier implements Identifier {
-
+ private static final long serialVersionUID = 1L;
private final String name;
public TransactionIdentifier(String name) {
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-/**
- * Every time factory is added or removed, blank transaction is triggered to handle
- * {@link org.opendaylight.controller.config.spi.ModuleFactory#getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory, org.osgi.framework.BundleContext)}
- * functionality.
- */
public class BindingIndependentMappingServiceTracker implements ServiceTrackerCustomizer<BindingIndependentMappingService, BindingIndependentMappingService> {
private static final Logger logger = LoggerFactory.getLogger(BindingIndependentMappingServiceTracker.class);
BindingIndependentMappingService service = ctx.getService(moduleFactoryServiceReference);
this.service = service;
CodecRegistry codecRegistry = service.getCodecRegistry();
- logger.warn("Codec registry acquired {}", codecRegistry);
+ logger.debug("Codec registry acquired {}", codecRegistry);
activator.initConfigManager(ctx, codecRegistry);
return service;
}
}
@Override
- public void removedService(ServiceReference<BindingIndependentMappingService> moduleFactoryServiceReference, BindingIndependentMappingService o) {
+ public void removedService(ServiceReference<BindingIndependentMappingService> moduleFactoryServiceReference, BindingIndependentMappingService o) {
// TODO crash
}
}
return mock(CodecRegistry.class);
}
-
public static interface BundleContextServiceRegistrationHandler {
void handleServiceRegistration(Object serviceInstance);
--- /dev/null
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-subsystem</artifactId>
+ <version>0.2.4-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>config-module-archetype</artifactId>
+ <name>config-module-archetype</name>
+ <description>Archetype for new module managed by configuration subsystem</description>
+
+</project>
--- /dev/null
+<archetype>
+ <id>config-module-archetype</id>
+
+ <allowPartial>true</allowPartial>
+
+ <requiredProperties>
+ <requiredProperty key="module-name">
+ </requiredProperty>
+ <requiredProperty key="module-name-java-prefix">
+ </requiredProperty>
+ <requiredProperty key="module-implementation-name">
+ <defaultValue>impl</defaultValue>
+ </requiredProperty>
+ <requiredProperty key="config-api-yang-revision">
+ <defaultValue>2013-04-05</defaultValue>
+ </requiredProperty>
+ <requiredProperty key="config-api-version">
+ <defaultValue>0.2.4-SNAPSHOT</defaultValue>
+ </requiredProperty>
+ <requiredProperty key="yang-maven-plugin-version">
+ <defaultValue>0.6.2-SNAPSHOT</defaultValue>
+ </requiredProperty>
+ <requiredProperty key="revision">
+ <defaultValue>2014-01-31</defaultValue>
+ </requiredProperty>
+ <requiredProperty key="service-java-class">
+ <defaultValue>java.lang.AutoCloseable</defaultValue>
+ </requiredProperty>
+ <requiredProperty key="maven-bundle-plugin-version">
+ <defaultValue>2.4.0</defaultValue>
+ </requiredProperty>
+ <requiredProperty key="yang-namespace-mapping-from">
+ <defaultValue>urn:opendaylight:params:xml:ns:yang:controller</defaultValue>
+ </requiredProperty>
+ <requiredProperty key="yang-namespace-mapping-to">
+ <defaultValue>org.opendaylight.controller.config.yang</defaultValue>
+ </requiredProperty>
+
+ </requiredProperties>
+
+ <fileSets>
+ <fileSet filtered="true" encoding="UTF-8">
+ <directory>src/main/yang</directory>
+ </fileSet>
+ </fileSets>
+</archetype>
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>${groupId}</groupId>
+ <artifactId>${artifactId}</artifactId>
+ <version>${version}</version>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
+ <config.version>${config-api-version}</config.version>
+ <maven.bundle.version>${maven-bundle-plugin-version}</maven.bundle.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-api</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <version>${yang-maven-plugin-version}</version>
+ <executions>
+ <execution>
+ <id>config</id>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>
+ org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ </codeGeneratorClass>
+ <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+ <additionalConfiguration>
+ <namespaceToPackage1>
+ ${yang-namespace-mapping-from}==${yang-namespace-mapping-to}
+ </namespaceToPackage1>
+ </additionalConfiguration>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-jmx-generator-plugin</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ </dependencies>
+ </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>${jmxGeneratorPath}</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>${maven.bundle.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+ <Export-Package>
+ ${yang-namespace-mapping-to}.${module-name},
+ </Export-Package>
+ <Import-Package>
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+
+
+ </plugins>
+ </build>
+</project>
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module ${module-name}-${module-implementation-name} {
+
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config:${module-name}:${module-implementation-name}";
+ prefix "${module-name}-${module-implementation-name}";
+
+ import config { prefix config; revision-date ${config-api-yang-revision}; }
+ import ${module-name} { prefix ${module-name}; revision-date ${revision}; }
+
+ description
+ "This module contains the base YANG definitions for
+ ${module-name} ${module-implementation-name} implementation.";
+
+ revision "${revision}" {
+ description
+ "Initial revision.";
+ }
+
+ // This is the definition of a service implementation
+ identity ${module-name}-${module-implementation-name} {
+ base config:module-type;
+ config:provided-service ${module-name}:${module-name};
+ config:java-name-prefix ${module-name-java-prefix};
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case ${module-name}-${module-implementation-name} {
+ when "/config:modules/config:module/config:type = '${module-name}-${module-implementation-name}'";
+
+ leaf simple-attribute {
+ type uint32;
+ }
+
+ container dto-attribute {
+ leaf inner-attribute {
+ type string;
+ }
+ }
+
+ // Dependency attribute demonstration, the config:required-identity points to a service type
+ // In this case it is the same service type as this implementation provides: ${module-name}
+ container dependency-attribute {
+ uses config:service-ref {
+ refine type {
+ mandatory false;
+ config:required-identity ${module-name}:${module-name};
+ }
+ }
+ }
+
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// vi: set smarttab et sw=4 tabstop=4:
+module ${module-name} {
+
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config:${module-name}";
+ prefix "${module-name}";
+
+ import config { prefix config; revision-date ${config-api-yang-revision}; }
+
+ description
+ "This module contains the base YANG definitions for
+ ${module-name} services.";
+
+ revision "${revision}" {
+ description
+ "Initial revision.";
+ }
+
+ // This is the definition of a service
+ identity ${module-name} {
+
+ base "config:service-type";
+
+ // TODO modify the java class
+ config:java-class " ${service-java-class}";
+ }
+}
\ No newline at end of file
package org.opendaylight.controller.config.persist.storage.file.xml.model;
final class PersistException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
public PersistException(String s, Exception e) {
super(s, e);
@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,
<?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<!-- vi: set et smarttab sw=4 tabstop=4: --><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<module>yang-test-plugin</module>
<module>shutdown-api</module>
<module>shutdown-impl</module>
+ <module>config-module-archetype</module>
</modules>
<profiles>
</goals>
</pluginExecutionFilter>
<action>
- <ignore />
+ <ignore/>
</action>
</pluginExecution>
</pluginExecutions>
</plugins>
</pluginManagement>
</build>
-</project>
+</project>
\ No newline at end of file
import org.opendaylight.yangtools.yang.common.QName;
public class NameConflictException extends RuntimeException {
-
+ private static final long serialVersionUID = 1L;
private static final String messageBlueprint = "Name conflict for name: %s, first defined in: %s, then defined in: %s";
private final String conflictingName;
private final QName secondParentQName;
@Test
public void testReadingIdentities_threadsJavaModule() {
- Map<String /* identity name */, Optional<QName>> expectedIdentitiesToBases = new HashMap(){{
+ Map<String /* identity name */, Optional<QName>> expectedIdentitiesToBases = new HashMap<String, Optional<QName>>(){
+ private static final long serialVersionUID = 1L;
+
+ {
put(ModuleMXBeanEntryTest.EVENTBUS_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
put(ModuleMXBeanEntryTest.ASYNC_EVENTBUS_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
put(ModuleMXBeanEntryTest.THREADFACTORY_NAMING_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
put(ModuleMXBeanEntryTest.THREADPOOL_DYNAMIC_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
- put("thread-rpc-context", Optional.absent());
+ put("thread-rpc-context", Optional.<QName>absent());
put(ModuleMXBeanEntryTest.THREADPOOL_REGISTRY_IMPL_NAME, Optional.of(MODULE_TYPE_Q_NAME));
}};
</dependency>
</dependencies>
+
+
<build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>
+ org.opendaylight.controller
+ </groupId>
+ <artifactId>
+ yang-test-plugin
+ </artifactId>
+ <versionRange>
+ [0.2.3,)
+ </versionRange>
+ <goals>
+ <goal>
+ delete-sources
+ </goal>
+ <goal>
+ process-sources
+ </goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore/>
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+
<plugins>
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
public abstract class ConfigurationObject implements Serializable {
private static final long serialVersionUID = 1L;
- private static final String DEFAULT_REGEX = "^[\\w-\\+\\*\\/\\.\\(\\)\\[\\]\\@]{1,256}$";
+ private static final String DEFAULT_REGEX = "^[\\w-=\\+\\*\\.\\(\\)\\[\\]\\@\\|\\:]{1,256}$";
private static final String REGEX_PROP_NAME = "resourceNameRegularExpression";
private static String regex;
* resource name regular expression, false otherwise
*/
protected boolean isValidResourceName(String name) {
- return (name != null) ? name.matches(regex) : false;
+ return name != null && name.matches(regex);
}
/**
* 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());
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) {
<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>
+ <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>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>
<!-- config-->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
</dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-codec-http</artifactId>
+ </dependency>
<!-- testing dependencies I'm pretty sure we should trim -->
<dependency>
for (FlowEntryInstall installEntry : toInstallSafe) {
// Install and update database
- Status ret = addEntriesInternal(installEntry, async);
+ Status ret = addEntryInternal(installEntry, async);
if (ret.isSuccess()) {
oneSucceded = true;
}
// Install new entries
for (FlowEntryInstall newEntry : toInstallSafe) {
- succeeded = this.addEntriesInternal(newEntry, async);
+ succeeded = this.addEntryInternal(newEntry, async);
}
} else {
/*
/**
* This is the function that modifies the final container flows merged
* entries on the network node and update the database. It expects that all
- * the validity checks are passed
+ * the validity checks are passed.
+ * This function is supposed to be called only on the controller on which
+ * the IFRM call is executed.
*
* @param currentEntries
* @param newEntries
* contain the unique id assigned to this request
*/
private Status modifyEntryInternal(FlowEntryInstall currentEntries, FlowEntryInstall newEntries, boolean async) {
+ Status status = new Status(StatusCode.UNDEFINED);
FlowEntryDistributionOrderFutureTask futureStatus =
distributeWorkOrder(currentEntries, newEntries, UpdateType.CHANGED);
if (futureStatus != null) {
- Status retStatus = new Status(StatusCode.UNDEFINED);
try {
- retStatus = futureStatus.get();
- if (retStatus.getCode()
+ status = futureStatus.get();
+ if (status.getCode()
.equals(StatusCode.TIMEOUT)) {
// A timeout happened, lets cleanup the workMonitor
workMonitor.remove(futureStatus.getOrder());
} catch (ExecutionException e) {
log.error("", e);
}
- return retStatus;
} else {
// Modify the flow on the network node
- Status status = async ? programmer.modifyFlowAsync(currentEntries.getNode(), currentEntries.getInstall()
- .getFlow(), newEntries.getInstall()
- .getFlow()) : programmer.modifyFlow(currentEntries.getNode(), currentEntries.getInstall()
- .getFlow(), newEntries.getInstall()
- .getFlow());
+ status = modifyEntryInHw(currentEntries, newEntries, async);
+ }
- if (!status.isSuccess()) {
- log.trace("SDN Plugin failed to program the flow: {}. The failure is: {}", newEntries.getInstall(),
- status.getDescription());
- return status;
- }
+ if (!status.isSuccess()) {
+ log.trace("{} SDN Plugin failed to program the flow: {}. The failure is: {}",
+ (futureStatus != null) ? "Remote" : "Local", newEntries.getInstall(), status.getDescription());
+ return status;
+ }
- log.trace("Modified {} => {}", currentEntries.getInstall(), newEntries.getInstall());
+ log.trace("Modified {} => {}", currentEntries.getInstall(), newEntries.getInstall());
- // Update DB
- newEntries.setRequestId(status.getRequestId());
- updateSwViews(currentEntries, false);
- updateSwViews(newEntries, true);
+ // Update DB
+ newEntries.setRequestId(status.getRequestId());
+ updateSwViews(currentEntries, false);
+ updateSwViews(newEntries, true);
- return status;
- }
+ return status;
+ }
+
+ private Status modifyEntryInHw(FlowEntryInstall currentEntries, FlowEntryInstall newEntries, boolean async) {
+ return async ? programmer.modifyFlowAsync(currentEntries.getNode(), currentEntries.getInstall().getFlow(),
+ newEntries.getInstall().getFlow()) : programmer.modifyFlow(currentEntries.getNode(), currentEntries
+ .getInstall().getFlow(), newEntries.getInstall().getFlow());
}
/**
* This is the function that removes the final container flows merged entry
* from the network node and update the database. It expects that all the
* validity checks are passed
+ * This function is supposed to be called only on the controller on which
+ * the IFRM call is executed.
*
* @param entry
* the flow entry to remove
* contain the unique id assigned to this request
*/
private Status removeEntryInternal(FlowEntryInstall entry, boolean async) {
+ Status status = new Status(StatusCode.UNDEFINED);
FlowEntryDistributionOrderFutureTask futureStatus = distributeWorkOrder(entry, null, UpdateType.REMOVED);
if (futureStatus != null) {
- Status retStatus = new Status(StatusCode.UNDEFINED);
try {
- retStatus = futureStatus.get();
- if (retStatus.getCode()
- .equals(StatusCode.TIMEOUT)) {
+ status = futureStatus.get();
+ if (status.getCode().equals(StatusCode.TIMEOUT)) {
// A timeout happened, lets cleanup the workMonitor
workMonitor.remove(futureStatus.getOrder());
}
} catch (ExecutionException e) {
log.error("", e);
}
- return retStatus;
} else {
// Mark the entry to be deleted (for CC just in case we fail)
entry.toBeDeleted();
// Remove from node
- Status status = async ? programmer.removeFlowAsync(entry.getNode(), entry.getInstall()
- .getFlow()) : programmer.removeFlow(entry.getNode(), entry.getInstall()
- .getFlow());
-
- if (!status.isSuccess()) {
- log.trace("SDN Plugin failed to remove the flow: {}. The failure is: {}", entry.getInstall(),
- status.getDescription());
- return status;
- }
- log.trace("Removed {}", entry.getInstall());
-
- // Update DB
- updateSwViews(entry, false);
+ status = removeEntryInHw(entry, async);
+ }
+ if (!status.isSuccess()) {
+ log.trace("{} SDN Plugin failed to remove the flow: {}. The failure is: {}",
+ (futureStatus != null) ? "Remote" : "Local", entry.getInstall(), status.getDescription());
return status;
}
+
+ log.trace("Removed {}", entry.getInstall());
+
+ // Update DB
+ updateSwViews(entry, false);
+
+ return status;
+ }
+
+ private Status removeEntryInHw(FlowEntryInstall entry, boolean async) {
+ return async ? programmer.removeFlowAsync(entry.getNode(), entry.getInstall().getFlow()) : programmer
+ .removeFlow(entry.getNode(), entry.getInstall().getFlow());
}
/**
* on the network node and updates the database. It expects that all the
* validity and conflict checks are passed. That means it does not check
* whether this flow would conflict or overwrite an existing one.
+ * This function is supposed to be called only on the controller on which
+ * the IFRM call is executed.
*
* @param entry
* the flow entry to install
* @return the status of this request. In case of asynchronous call, it will
* contain the unique id assigned to this request
*/
- private Status addEntriesInternal(FlowEntryInstall entry, boolean async) {
+ private Status addEntryInternal(FlowEntryInstall entry, boolean async) {
+ Status status = new Status(StatusCode.UNDEFINED);
FlowEntryDistributionOrderFutureTask futureStatus = distributeWorkOrder(entry, null, UpdateType.ADDED);
if (futureStatus != null) {
- Status retStatus = new Status(StatusCode.UNDEFINED);
try {
- retStatus = futureStatus.get();
- if (retStatus.getCode()
- .equals(StatusCode.TIMEOUT)) {
+ status = futureStatus.get();
+ if (status.getCode().equals(StatusCode.TIMEOUT)) {
// A timeout happened, lets cleanup the workMonitor
workMonitor.remove(futureStatus.getOrder());
}
} catch (ExecutionException e) {
log.error("", e);
}
- return retStatus;
} else {
- // Install the flow on the network node
- Status status = async ? programmer.addFlowAsync(entry.getNode(), entry.getInstall()
- .getFlow()) : programmer.addFlow(entry.getNode(), entry.getInstall()
- .getFlow());
+ status = addEntryInHw(entry, async);
+ }
- if (!status.isSuccess()) {
- log.trace("SDN Plugin failed to program the flow: {}. The failure is: {}", entry.getInstall(),
- status.getDescription());
- return status;
- }
+ if (!status.isSuccess()) {
+ log.trace("{} SDN Plugin failed to program the flow: {}. The failure is: {}",
+ (futureStatus != null) ? "Remote" : "Local", entry.getInstall(), status.getDescription());
+ return status;
+ }
+
+ log.trace("Added {}", entry.getInstall());
- log.trace("Added {}", entry.getInstall());
+ // Update DB
+ entry.setRequestId(status.getRequestId());
+ updateSwViews(entry, true);
- // Update DB
- entry.setRequestId(status.getRequestId());
- updateSwViews(entry, true);
+ return status;
+ }
- return status;
- }
+ private Status addEntryInHw(FlowEntryInstall entry, boolean async) {
+ // Install the flow on the network node
+ return async ? programmer.addFlowAsync(entry.getNode(), entry.getInstall().getFlow()) : programmer.addFlow(
+ entry.getNode(), entry.getInstall().getFlow());
}
/**
FlowEntryInstall feiNew = workOrder.get(fe);
switch (fe.getUpType()) {
case ADDED:
- gotStatus = addEntriesInternal(feiCurrent, false);
+ gotStatus = addEntryInHw(feiCurrent, false);
break;
case CHANGED:
- gotStatus = modifyEntryInternal(feiCurrent, feiNew, false);
+ gotStatus = modifyEntryInHw(feiCurrent, feiNew, false);
break;
case REMOVED:
- gotStatus = removeEntryInternal(feiCurrent, false);
+ gotStatus = removeEntryInHw(feiCurrent, false);
break;
}
// Remove the Order
return new IPHostId(addr);
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("IP=[");
+ if (this.ipAddress != null) {
+ builder.append(this.ipAddress.getHostAddress());
+ }
+ builder.append("]");
+ return (builder.toString());
+ }
}
return new IPMacHostId(ip, mac);
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("IP=[");
+ if (this.ipAddress != null) {
+ builder.append(this.ipAddress.getHostAddress());
+ }
+ builder.append("]")
+ .append("MAC=[");
+ if (this.macAddr != null) {
+ builder.append(this.macAddr.toString());
+ }
+ builder.append("]");
+ return (builder.toString());
+ }
}
}
}
+ /*
+ * This thread runs every 4 seconds
+ */
+
class OutStandingARPHandler extends TimerTask {
@Override
public void run() {
return;
}
ARPPending arphost;
- /* This routine runs every 4 seconds */
- logger.trace("Number of Entries in ARP Pending/Failed Lists: ARPPendingList = {}, failedARPReqList = {}",
- ARPPendingList.size(), failedARPReqList.size());
- for (Entry<IHostId, ARPPending> entry : ARPPendingList.entrySet()) {
- arphost = entry.getValue();
-
- if (hostsDB.containsKey(arphost.getHostId())) {
- // this host is already learned, shouldn't be in
- // ARPPendingList
- // Remove it and continue
- logger.warn("Learned Host {} found in ARPPendingList", decodeIPFromId(arphost.getHostId()));
- ARPPendingList.remove(entry.getKey());
- continue;
- }
- if (arphost.getSent_count() < hostRetryCount) {
- /*
- * No reply has been received of first ARP Req, send the
- * next one. Before sending the ARP, check if ARPHandler is
- * available or not
- */
- if (hostFinder == null) {
- logger.warn("ARPHandler Services are not available for Outstanding ARPs");
+ try {
+ for (Entry<IHostId, ARPPending> entry : ARPPendingList.entrySet()) {
+ arphost = entry.getValue();
+
+ if (hostsDB.containsKey(arphost.getHostId())) {
+ // this host is already learned, shouldn't be in
+ // ARPPendingList
+ // Remove it and continue
+ logger.warn("Learned Host {} found in ARPPendingList", decodeIPFromId(arphost.getHostId()));
+ ARPPendingList.remove(entry.getKey());
continue;
}
- for (IHostFinder hf : hostFinder) {
- hf.find(decodeIPFromId(arphost.getHostId()));
- }
- arphost.sent_count++;
- logger.debug("ARP Sent from ARPPending List, IP: {}", decodeIPFromId(arphost.getHostId()));
- } else if (arphost.getSent_count() >= hostRetryCount) {
- /*
- * ARP requests have been sent without receiving a reply,
- * remove this from the pending list
- */
- ARPPendingList.remove(entry.getKey());
- logger.debug("ARP reply not received after multiple attempts, removing from Pending List IP: {}",
- decodeIPFromId(arphost.getHostId()));
- /*
- * Add this host to a different list which will be processed
- * on link up events
- */
- logger.debug("Adding the host to FailedARPReqList IP: {}", decodeIPFromId(arphost.getHostId()));
- failedARPReqList.put(entry.getKey(), arphost);
+ if (arphost.getSent_count() < hostRetryCount) {
+ /*
+ * No reply has been received of first ARP Req, send the
+ * next one. Before sending the ARP, check if ARPHandler
+ * is available or not
+ */
+ if (hostFinder == null) {
+ logger.warn("ARPHandler Services are not available for Outstanding ARPs");
+ continue;
+ }
+ for (IHostFinder hf : hostFinder) {
+ hf.find(decodeIPFromId(arphost.getHostId()));
+ }
+ arphost.sent_count++;
+ logger.debug("ARP Sent from ARPPending List, IP: {}", decodeIPFromId(arphost.getHostId()));
+ } else if (arphost.getSent_count() >= hostRetryCount) {
+ /*
+ * ARP requests have been sent without receiving a
+ * reply, remove this from the pending list
+ */
+ ARPPendingList.remove(entry.getKey());
+ logger.debug(
+ "ARP reply not received after multiple attempts, removing from Pending List IP: {}",
+ decodeIPFromId(arphost.getHostId()));
+ /*
+ * Add this host to a different list which will be
+ * processed on link up events
+ */
+ logger.debug("Adding the host to FailedARPReqList IP: {}", decodeIPFromId(arphost.getHostId()));
+ failedARPReqList.put(entry.getKey(), arphost);
- } else {
- logger.error("Inavlid arp_sent count for entry: {}", entry);
+ } else {
+ logger.error("Inavlid arp_sent count for entry: {}", entry);
+ }
}
+ } catch (IllegalStateException e) {
+ logger.debug("IllegalStateException Received by OutStandingARPHandler from: {}", e.getMessage());
}
}
}
private class ARPRefreshHandler extends TimerTask {
@Override
public void run() {
- if (stopping) {
+ if ((clusterContainerService != null) && !clusterContainerService.amICoordinator()) {
return;
}
- if ((clusterContainerService != null) && !clusterContainerService.amICoordinator()) {
+ if (stopping) {
return;
}
if (!hostRefresh) {
logger.error("ARPRefreshHandler(): hostsDB is not allocated yet:");
return;
}
- for (Entry<IHostId, HostNodeConnector> entry : hostsDB.entrySet()) {
- HostNodeConnector host = entry.getValue();
- if (host.isStaticHost()) {
- /* this host was learned via API3, don't age it out */
- continue;
- }
-
- short arp_cntdown = host.getArpSendCountDown();
- arp_cntdown--;
- if (arp_cntdown > hostRetryCount) {
- host.setArpSendCountDown(arp_cntdown);
- } else if (arp_cntdown <= 0) {
- /*
- * No ARP Reply received in last 2 minutes, remove this host
- * and inform applications
- */
- removeKnownHost(entry.getKey());
- notifyHostLearnedOrRemoved(host, false);
- } else if (arp_cntdown <= hostRetryCount) {
- /*
- * Use the services of arphandler to check if host is still
- * there
- */
- if (logger.isTraceEnabled()) {
- logger.trace(
- "ARP Probing ({}) for {}({})",
- new Object[] { arp_cntdown, host.getNetworkAddress().getHostAddress(),
- HexEncode.bytesToHexString(host.getDataLayerAddressBytes()) });
+ try {
+ for (Entry<IHostId, HostNodeConnector> entry : hostsDB.entrySet()) {
+ HostNodeConnector host = entry.getValue();
+ if (host.isStaticHost()) {
+ /* this host was learned via API3, don't age it out */
+ continue;
}
- host.setArpSendCountDown(arp_cntdown);
- if (hostFinder == null) {
+
+ short arp_cntdown = host.getArpSendCountDown();
+ arp_cntdown--;
+ if (arp_cntdown > hostRetryCount) {
+ host.setArpSendCountDown(arp_cntdown);
+ } else if (arp_cntdown <= 0) {
/*
- * If hostfinder is not available, then can't send the
- * probe. However, continue the age out the hosts since
- * we don't know if the host is indeed out there or not.
+ * No ARP Reply received in last 2 minutes, remove this
+ * host and inform applications
*/
- logger.trace("ARPHandler is not avaialable, can't send the probe");
- continue;
- }
- for (IHostFinder hf : hostFinder) {
- hf.probe(host);
+ removeKnownHost(entry.getKey());
+ notifyHostLearnedOrRemoved(host, false);
+ } else if (arp_cntdown <= hostRetryCount) {
+ /*
+ * Use the services of arphandler to check if host is
+ * still there
+ */
+ if (logger.isTraceEnabled()) {
+ logger.trace(
+ "ARP Probing ({}) for {}({})",
+ new Object[] { arp_cntdown, host.getNetworkAddress().getHostAddress(),
+ HexEncode.bytesToHexString(host.getDataLayerAddressBytes()) });
+ }
+ host.setArpSendCountDown(arp_cntdown);
+ if (hostFinder == null) {
+ /*
+ * If hostfinder is not available, then can't send
+ * the probe. However, continue the age out the
+ * hosts since we don't know if the host is indeed
+ * out there or not.
+ */
+ logger.trace("ARPHandler is not avaialable, can't send the probe");
+ continue;
+ }
+ for (IHostFinder hf : hostFinder) {
+ hf.probe(host);
+ }
}
}
+ } catch (IllegalStateException e) {
+ logger.debug("IllegalStateException Received by ARPRefreshHandler from: {}", e.getMessage());
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>commons.opendaylight</artifactId>
- <version>1.4.2-SNAPSHOT</version>
- <relativePath>../../commons/opendaylight</relativePath>
- </parent>
- <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:Main</url>
- <tag>HEAD</tag>
- </scm>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.opendaylight</artifactId>
+ <version>1.4.2-SNAPSHOT</version>
+ <relativePath>../../commons/opendaylight</relativePath>
+ </parent>
+ <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:Main</url>
+ <tag>HEAD</tag>
+ </scm>
- <artifactId>logging.bridge</artifactId>
- <version>0.4.2-SNAPSHOT</version>
- <packaging>bundle</packaging>
+ <artifactId>logging.bridge</artifactId>
+ <version>0.4.2-SNAPSHOT</version>
+ <packaging>bundle</packaging>
- <dependencies>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.eclipse.osgi</artifactId>
- </dependency>
- </dependencies>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>equinoxSDK381</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <version>${bundle.plugin.version}</version>
- <extensions>true</extensions>
- <configuration>
- <instructions>
- <Import-Package>
- org.slf4j,
- org.osgi.framework,
- org.osgi.service.log
- </Import-Package>
- <Bundle-Activator>
- org.opendaylight.controller.logging.bridge.internal.Activator
- </Bundle-Activator>
- </instructions>
- <manifestLocation>${project.basedir}/META-INF</manifestLocation>
- </configuration>
- </plugin>
- </plugins>
- </build>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>${bundle.plugin.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ org.slf4j,
+ org.osgi.framework,
+ org.osgi.service.log
+ </Import-Package>
+ <Bundle-Activator>
+ org.opendaylight.controller.logging.bridge.internal.Activator
+ </Bundle-Activator>
+ </instructions>
+ <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
if (this.logger != null) {
switch (entry.getLevel()) {
case LogService.LOG_DEBUG:
- this.logger.debug("Bundle:{} Message:{} Exception:{}", entry.getBundle()
+ this.logger.debug("Bundle:{} Message:{}", entry.getBundle()
.getSymbolicName(), entry.getMessage(), entry.getException());
break;
case LogService.LOG_INFO:
- this.logger.info("Bundle:{} Message:{} Exception:{}", entry.getBundle()
+ this.logger.info("Bundle:{} Message:{}", entry.getBundle()
.getSymbolicName(), entry.getMessage(), entry.getException());
break;
case LogService.LOG_WARNING:
- this.logger.warn("Bundle:{} Message:{} Exception:{}", entry.getBundle()
+ this.logger.warn("Bundle:{} Message:{}", entry.getBundle()
.getSymbolicName(), entry.getMessage(), entry.getException());
break;
case LogService.LOG_ERROR:
- this.logger.error("Bundle:{} Message:{} Exception:{}", entry.getBundle()
+ this.logger.error("Bundle:{} Message:{}", entry.getBundle()
.getSymbolicName(), entry.getMessage(), entry.getException());
break;
}
--- /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.logging.bridge.internal;
+
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+public class LogListenerImplTest {
+ private static final Logger logger = LoggerFactory.getLogger(LogListenerImplTest.class);
+
+ @Test
+ public void test() {
+ LogListenerImpl tested = new LogListenerImpl(logger);
+ tested.logged(getEntry("m1", null));
+ tested.logged(getEntry("m2", new RuntimeException()));
+ }
+
+ private LogEntry getEntry(final String message, final Exception e) {
+ return new LogEntry() {
+ @Override
+ public Bundle getBundle() {
+ Bundle mock = mock(Bundle.class);
+ doReturn(null).when(mock).getSymbolicName();
+ return mock;
+ }
+
+ @Override
+ public ServiceReference getServiceReference() {
+ return null;
+ }
+
+ @Override
+ public int getLevel() {
+ return LogService.LOG_INFO;
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public Throwable getException() {
+ return e;
+ }
+
+ @Override
+ public long getTime() {
+ return 0;
+ }
+ };
+ }
+
+}
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);
+ }
+ }
+}
import org.opendaylight.controller.sal.common.util.Futures;
import org.opendaylight.controller.sal.common.util.Rpcs;
import org.opendaylight.controller.sal.compatibility.InventoryMapping;
-import org.opendaylight.controller.sal.compatibility.NodeMapping;
import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils;
-import org.opendaylight.controller.sal.core.ConstructionException;
import org.opendaylight.controller.sal.flowprogrammer.Flow;
import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener;
import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
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>
<dependency>
<groupId>${project.groupId}</groupId>
import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
revision "2013-10-26" {
- description "Initial revision of macth types";
+ description "Initial revision of match types";
}
grouping "mac-address-filter" {
grouping set-field-match {
list set-field-match {
+ key "match-type";
leaf match-type {
type identityref {
base match-field;
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>opendaylight-l2-types</artifactId>
- <version>2013.08.27.3</version>
</dependency>
</dependencies>
<packaging>bundle</packaging>
import yang-ext {prefix ext; revision-date "2013-07-09";}
import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
- import opendaylight-flow-types {prefix types;revision-date "2013-10-26";}
+ import opendaylight-flow-types {prefix types;revision-date "2013-10-26";}
+ import opendaylight-group-types {prefix group-type;revision-date 2013-10-18;}
+ import opendaylight-meter-types {prefix meter-type;revision-date "2013-09-18";}
import flow-capable-transaction {prefix tr;}
import flow-errors {prefix error;}
uses error:error-message;
uses tr:transaction-aware;
uses tr:transaction-metadata;
+ choice object-reference {
+ case flow-ref{
+ leaf flow-ref {
+ type types:flow-ref;
+ }
+ }
+ case group-ref{
+ leaf group-ref {
+ type group-type:group-ref;
+ }
+ }
+ case meter-ref{
+ leaf meter-ref {
+ type meter-type:meter-ref;
+ }
+ }
+ }
+ leaf node {
+ ext:context-reference "inv:node-context";
+ type inv:node-ref;
+ }
+
}
notification node-experimenter-error-notification {
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
- <!-- Java Versions -->
- <maven.compiler.source>1.7</maven.compiler.source>
- <maven.compiler.target>1.7</maven.compiler.target>
<!-- Plugin Versions -->
<bundle.plugin.version>2.4.0</bundle.plugin.version>
- <releaseplugin.version>2.3.2</releaseplugin.version>
+ <maven.clean.plugin.version>2.5</maven.clean.plugin.version>
<!-- Dependency Versions -->
- <slf4j.version>1.7.2</slf4j.version>
- <guava.version>14.0.1</guava.version>
- <osgi.core.version>5.0.0</osgi.core.version>
- <junit.version>4.8.1</junit.version>
<mockito.version>1.9.5</mockito.version>
<xtend.version>2.4.3</xtend.version>
- <maven.clean.plugin.version>2.5</maven.clean.plugin.version>
- <jacoco.version>0.5.3.201107060350</jacoco.version>
<!-- Sonar properties using jacoco to retrieve integration test results -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sal.version>0.7.1-SNAPSHOT</sal.version>
</properties>
- <pluginRepositories>
- <!-- OpenDayLight Repo Mirror -->
- <pluginRepository>
- <id>opendaylight-mirror</id>
- <name>opendaylight-mirror</name>
- <url>${nexusproxy}/groups/public/</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- <releases>
- <enabled>true</enabled>
- <updatePolicy>never</updatePolicy>
- </releases>
- </pluginRepository>
- <!-- OpenDayLight Snapshot artifact -->
- <pluginRepository>
- <id>opendaylight-snapshot</id>
- <name>opendaylight-snapshot</name>
- <url> ${nexusproxy}/repositories/opendaylight.snapshot/</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- <releases>
- <enabled>false</enabled>
- </releases>
- </pluginRepository>
- </pluginRepositories>
-
-
- <repositories>
- <!-- OpenDayLight Repo Mirror -->
- <repository>
- <id>opendaylight-mirror</id>
- <name>opendaylight-mirror</name>
- <url>${nexusproxy}/groups/public/</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- <releases>
- <enabled>true</enabled>
- <updatePolicy>never</updatePolicy>
- </releases>
- </repository>
- <!-- OpenDayLight Snapshot artifact -->
- <repository>
- <id>opendaylight-snapshot</id>
- <name>opendaylight-snapshot</name>
- <url> ${nexusproxy}/repositories/opendaylight.snapshot/</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- <releases>
- <enabled>false</enabled>
- </releases>
- </repository>
- </repositories>
-
- <distributionManagement>
- <!-- OpenDayLight Released artifact -->
- <repository>
- <id>opendaylight-release</id>
- <url>${nexusproxy}/repositories/opendaylight.release/</url>
- </repository>
- <!-- OpenDayLight Snapshot artifact -->
- <snapshotRepository>
- <id>opendaylight-snapshot</id>
- <url>${nexusproxy}/repositories/opendaylight.snapshot/</url>
- </snapshotRepository>
- <!-- Site deployment -->
- <site>
- <id>website</id>
- <url>${sitedeploy}</url>
- </site>
- </distributionManagement>
-
-
<dependencyManagement>
<dependencies>
<dependency>
<version>1.4.01</version>
</dependency>
- <!-- YANG Tools Dependencies -->
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-binding</artifactId>
- <version>${yangtools.version}</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-model-util</artifactId>
- <version>${yangtools.version}</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-common</artifactId>
- <version>${yangtools.version}</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-api</artifactId>
- <version>${yangtools.version}</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-impl</artifactId>
- <version>${yangtools.version}</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-model-api</artifactId>
- <version>${yangtools.version}</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-util</artifactId>
- <version>${yangtools.version}</version>
- </dependency>
<!-- SAL Dependencies -->
<dependency>
<groupId>${project.groupId}</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>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- <version>${guava.version}</version>
- </dependency>
<dependency>
<groupId>org.eclipse.xtend</groupId>
<artifactId>org.eclipse.xtend.lib</artifactId>
<artifactId>org.osgi.core</artifactId>
<version>${osgi.core.version}</version>
</dependency>
- <!-- Testing Dependencies -->
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>${junit.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-all</artifactId>
- <version>${mockito.version}</version>
- <scope>test</scope>
- </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>binding-generator-impl</artifactId>
<artifactId>yang-parser-impl</artifactId>
<version>${yangtools.version}</version>
</dependency>
+
+ <!-- Testing Dependencies -->
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>${mockito.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-release-plugin</artifactId>
- <version>${releaseplugin.version}</version>
- </plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
*/
package org.opendaylight.controller.sal.binding.api;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
public abstract class AbstractBindingAwareConsumer extends AbstractBrokerAwareActivator implements BindingAwareConsumer {
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
public abstract class AbstractBindingAwareProvider extends AbstractBrokerAwareActivator implements BindingAwareProvider {
-
+
@Override
protected final void onBrokerAvailable(BindingAwareBroker broker, BundleContext context) {
ProviderContext ctx = broker.registerProvider(this, context);
public Collection<? extends RpcService> getImplementations() {
return Collections.emptySet();
}
-
+
/**
* Initialization of consumer context.
- *
+ *
* {@link ProviderContext} is replacement of {@link ConsumerContext}
* so this method is not needed in case of Provider.
- *
+ *
*/
@Deprecated
@Override
import org.opendaylight.controller.md.sal.common.api.notify.NotificationPublishService;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.Notification;
public interface NotificationProviderService extends NotificationService, NotificationPublishService<Notification> {
/**
* Deprecated. Use {@link #publish(Notification)}.
- *
+ *
* @param notification
*/
@Deprecated
/**
* Deprecated. Use {@link #publish(Notification,ExecutorService)}.
- *
+ *
* @param notification
*/
@Deprecated
/**
* Publishes a notification.
- *
+ *
* @param Notification
* notification to publish.
- *
+ *
*/
@Override
void publish(Notification notification);
/**
* Publishes a notification, listener calls are done in provided executor.
- *
+ *
*/
@Override
void publish(Notification notification, ExecutorService service);
*/
package org.opendaylight.controller.sal.binding.api;
-import org.opendaylight.controller.md.sal.common.api.notify.NotificationSubscriptionService;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.Notification;
public interface NotificationService extends BindingAwareService {
/**
- *
+ *
* Deprecated: use {@link #addNotificationListener(Class, NotificationListener)} istead.
- *
+ *
* @param listener
*/
@Deprecated
<T extends Notification> void addNotificationListener(Class<T> notificationType, NotificationListener<T> listener);
/**
- *
+ *
* Deprecated: use {@link #addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener)} istead.
- *
+ *
* @param listener
*/
@Deprecated
@Deprecated
<T extends Notification> void removeNotificationListener(Class<T> notificationType, NotificationListener<T> listener);
-
+
/**
* Register a generic listener for specified notification type only.
- *
+ *
* @param notificationType
* @param listener
* @return Registration for listener. To unregister listener invoke {@link Registration#close()} method.
* Register a listener which implements generated notification interfaces derived from
* {@link org.opendaylight.yangtools.yang.binding.NotificationListener}.
* Listener is registered for all notifications present in implemented interfaces.
- *
+ *
* @param listener
* @return Registration for listener. To unregister listener invoke {@link Registration#close()} method.
*/
* 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);
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.RpcService;
/**
* Interface defining provider's access to the Rpc Registry which could be used
* to register their implementations of service to the MD-SAL.
- *
+ *
* @author ttkacik
- *
+ *
*/
public interface RpcProviderRegistry extends //
RpcConsumerRegistry, //
RouteChangePublisher<RpcContextIdentifier, InstanceIdentifier<?>> {
/**
* Registers an global RpcService implementation.
- *
+ *
* @param type
* @param implementation
* @return
throws IllegalStateException;
/**
- *
+ *
* Register an Routed RpcService where routing is determined on annotated
* (in YANG model) context-reference and value of annotated leaf.
- *
+ *
* @param type
* Type of RpcService, use generated interface class, not your
* implementation clas
* Implementation of RpcService
* @return Registration object for routed Rpc which could be used to close
* an
- *
+ *
* @throws IllegalStateException
*/
<T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> type, T implementation)
import java.util.concurrent.Future;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
import org.opendaylight.controller.md.sal.common.api.data.DataModification;
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.common.RpcResult;
/**
* Returns an unique identifier for transaction
- *
+ *
*/
@Override
public Object getIdentifier();
-
+
/**
* Initiates a two-phase commit of candidate data.
- *
+ *
* <p>
* The {@link Consumer} could initiate a commit of candidate data
- *
+ *
* <p>
* The successful commit changes the state of the system and may affect
* several components.
- *
+ *
* <p>
* The effects of successful commit of data are described in the
* specifications and YANG models describing the {@link Provider} components
* of controller. It is assumed that {@link Consumer} has an understanding
* of this changes.
- *
- *
+ *
+ *
* @see DataCommitHandler for further information how two-phase commit is
* processed.
* @param store
*/
@Override
public Future<RpcResult<TransactionStatus>> commit();
-
-
-
+
+
+
/**
* Register a listener for transaction
- *
+ *
* @param listener
* @return
*/
/**
* Listener for transaction state changes
- *
+ *
*
*/
public interface DataTransactionListener extends EventListener {
/**
* Callback is invoked after each transaction status change.
- *
+ *
* @param transaction Transaction
* @param status New status
*/
import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService;
import org.opendaylight.controller.md.sal.common.api.data.DataReader;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
*/
public interface DataProviderService extends DataBrokerService, DataProvisionService<InstanceIdentifier<? extends DataObject>, DataObject> {
-
+
/**
* Registers a data reader for particular subtree of overal YANG data tree.
- *
- * Registered data reader is called if anyone tries to read data from
+ *
+ * Registered data reader is called if anyone tries to read data from
* paths which are nested to provided path.
- *
+ *
* @param path Subpath which is handled by registered data reader
- * @param reader Instance of reader which
+ * @param reader Instance of reader which
* @return Registration object for reader. Invoking {@link Registration#close()} will unregister reader.
*/
Registration<DataReader<InstanceIdentifier<? extends DataObject>,DataObject>> registerDataReader(InstanceIdentifier<? extends DataObject> path,DataReader<InstanceIdentifier<? extends DataObject>,DataObject> reader);
package org.opendaylight.controller.sal.binding.api.data;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
/**
* Trigger for refreshing of the data exposed by the {@link Provider}
- *
- *
- *
+ *
+ *
+ *
*/
public interface DataRefresher extends BindingAwareProvider.ProviderFunctionality {
/**
* Fired when some component explicitly requested the data refresh.
- *
+ *
* The provider which exposed the {@link DataRefresher} should republish its
* provided data by editing the data in all affected data stores.
*/
*/
package org.opendaylight.controller.sal.binding.api.data;
-import java.util.Set;
-
import org.opendaylight.controller.md.sal.common.api.data.DataReader;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
/**
- * Utility interface which does type capture for BindingAware DataReader.
- *
- * @author
+ * Utility interface which does type capture for BindingAware DataReader.
+ *
+ * @author
*
*/
public interface RuntimeDataProvider extends ProviderFunctionality,DataReader<InstanceIdentifier<? extends DataObject>, DataObject> {
-
-
+
+
}
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.RpcService;
public interface MountInstance //
extends //
import java.util.EventListener;
-import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
/**
* Provider MountProviderService, this version allows access to MD-SAL services
* specific for this mountpoint and registration / provision of interfaces for
* mount point.
- *
+ *
* @author ttkacik
- *
+ *
*/
public interface MountProviderService extends MountService {
-
+
@Override
public MountProviderInstance getMountPoint(InstanceIdentifier<?> path);
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.RpcImplementation;
import org.opendaylight.yangtools.yang.binding.RpcService;
/**
* RpcRouter is responsible for selecting RpcService based on provided routing
* context identifier {@link RpcRoutingTable#getContextIdentifier()} and path in
* overal data tree (@link {@link InstanceIdentifier}.
- *
- *
+ *
+ *
* @author Tony Tkacik <ttkacik@cisco.com>
- *
+ *
* @param <T>
* Type of RpcService for which router provides routing information
* and route selection.
/**
* Returns a type of RpcService which is served by this instance of router.
- *
+ *
* @return type of RpcService which is served by this instance of router.
*/
Class<T> getServiceType();
-
-
+
+
/**
* Returns a instance of T which is associated with this router instance
* and routes messages based on routing tables.
- *
+ *
* @return type of RpcService which is served by this instance of router.
*/
T getInvocationProxy();
/**
* Returns a routing table for particular route context
- *
+ *
* @param routeContext
* @return Routing Table for particular route context.
*/
/**
* Returns an instance of RpcService which is responsible for processing
* particular path.
- *
+ *
* @param context
* Rpc Routing Context
* @param path
/**
* Returns a default fallback instance of RpcService which is responsible
* for handling all unknown imports.
- *
+ *
* @return default instance responsible for processing RPCs.
*/
T getDefaultService();
Set<Class<? extends BaseIdentity>> getContexts();
-
+
RoutedRpcRegistration<T> addRoutedRpcImplementation(T service);
-
+
RpcRegistration<T> registerDefaultService(T service);
}
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>
import org.opendaylight.controller.sal.binding.impl.forward.DomForwardingUtils;\r
import org.osgi.framework.BundleContext;\r
\r
-import com.google.common.util.concurrent.MoreExecutors;\r
-\r
/**\r
*\r
*/\r
*/
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 java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-
import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl;
import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
/**
*
*/
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 javassist.ClassPool;
-
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.Preconditions;
-
/**
*
*/
return delegate.getRpcQNamesFor(service);
}
+ @Override
+ public Optional<Class<? extends RpcService>> getRpcServiceClassFor(String namespace, String revision) {
+ return delegate.getRpcServiceClassFor(namespace,revision);
+ }
+
public DataContainer dataObjectFromDataDom(Class<? extends DataContainer> inputClass, CompositeNode domInput) {
return delegate.dataObjectFromDataDom(inputClass, domInput);
}
*/
package org.opendaylight.controller.sal.binding.codegen.impl;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
-import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
-import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
-import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper;
-import org.opendaylight.yangtools.yang.binding.BaseIdentity;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*;
+import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.setRoutingTable;
+import java.util.HashMap;
import java.util.Map;
import java.util.Set;
-import java.util.HashMap;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
-import org.opendaylight.yangtools.yang.binding.RpcImplementation;
-import org.opendaylight.controller.md.sal.common.api.routing.MutableRoutingTable;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper;
import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Map<Class<? extends BaseIdentity>, RpcRoutingTableImpl<? extends BaseIdentity, T>> mutableRoutingTables = new HashMap<>();
for (Class<? extends BaseIdentity> ctx : contexts) {
RpcRoutingTableImpl<? extends BaseIdentity, T> table = new RpcRoutingTableImpl<>(name,ctx,type);
-
+
@SuppressWarnings("rawtypes")
Map invokerView = table.getRoutes();
-
- setRoutingTable((RpcService) invocationProxy, ctx, invokerView);
+
+ setRoutingTable(invocationProxy, ctx, invokerView);
mutableRoutingTables.put(ctx, table);
table.registerRouteChangeListener(this);
}
*/
package org.opendaylight.controller.sal.binding.codegen.impl;
-import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
-import org.opendaylight.yangtools.yang.binding.BaseIdentity;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Mutable;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> listener;
private S defaultRoute;
-
+
public RpcRoutingTableImpl(String routerName,Class<C> contextType, Class<S> serviceType) {
super();
this.routerName = routerName;
@Override
public <L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
L listener) {
- return (ListenerRegistration<L>) new SingletonListenerRegistration<L>(listener);
+ return new SingletonListenerRegistration<L>(listener);
}
-
+
@Override
public Class<C> getIdentifier() {
return contextType;
@SuppressWarnings("unchecked")
public void updateRoute(InstanceIdentifier<?> path, S service) {
S previous = this.routes.put(path, service);
-
+
LOGGER.debug("Route {} updated to {} in routing table {}",path,service,this);
@SuppressWarnings("rawtypes")
RouteChangeListener listenerCapture = listener;
}
}
-
+
@Override
@SuppressWarnings("unchecked")
public void removeRoute(InstanceIdentifier<?> path) {
listenerCapture.onRouteChange(RoutingUtils.removalChange(contextType, path));
}
}
-
+
public void removeRoute(InstanceIdentifier<?> path, S service) {
@SuppressWarnings("rawtypes")
RouteChangeListener listenerCapture = listener;
public Map<InstanceIdentifier<?>, S> getRoutes() {
return unmodifiableRoutes;
}
-
+
protected void removeAllReferences(S service) {
-
+
}
-
-
+
+
@Override
public String toString() {
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
+import javassist.ClassPool;
+
import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import javassist.ClassPool;
-
public class SingletonHolder {
public static final ClassPool CLASS_POOL = new ClassPool();
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.concurrent.Future;\r
-import java.util.concurrent.atomic.AtomicLong;\r
-\r
-import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;\r
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;\r
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;\r
-import org.opendaylight.controller.sal.binding.impl.util.BindingAwareDataReaderRouter;\r
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;\r
-import org.opendaylight.yangtools.yang.binding.DataObject;\r
-import org.opendaylight.yangtools.yang.binding.DataRoot;\r
-import org.opendaylight.yangtools.yang.binding.Identifiable;\r
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
-import org.opendaylight.yangtools.yang.common.RpcResult;\r
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.binding.impl.util.BindingAwareDataReaderRouter;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataRoot;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.util.DataObjectReadingUtil;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+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
+\r
public AtomicLong getCreatedTransactionsCount() {\r
return createdTransactionsCount;\r
}\r
DataChangeListener changeListener) {\r
throw new UnsupportedOperationException("Deprecated");\r
}\r
- \r
+\r
@Override\r
public void close() throws Exception {\r
- \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.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction.DataTransactionListener;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-public class DataTransactionImpl extends AbstractDataTransaction<InstanceIdentifier<? extends DataObject>, DataObject>
+public class DataTransactionImpl extends AbstractDataTransaction<InstanceIdentifier<? extends DataObject>, DataObject>
implements DataModificationTransaction {
private final ListenerRegistry<DataTransactionListener> listeners = new ListenerRegistry<DataTransactionListener>();
-
-
-
+
+
+
public DataTransactionImpl(Object identifier,DataBrokerImpl dataBroker) {
super(identifier,dataBroker);
}
return listeners.register(listener);
}
+ @Override
protected void onStatusChange(TransactionStatus status) {
for (ListenerRegistration<DataTransactionListener> listenerRegistration : listeners) {
listenerRegistration.getInstance().onStatusUpdated(this, status);
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\r
+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
listenerToNotify = listenerToNotify + listeners.get(type as Class<? extends Notification>)\r
}\r
val tasks = listenerToNotify.map[new NotifyTask(it, notification)].toSet;\r
- executor.invokeAll(tasks);\r
+ submitAll(executor,tasks);\r
}\r
-\r
+ \r
+ 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();\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, //
*/
package org.opendaylight.controller.sal.binding.impl;
+import static com.google.common.base.Preconditions.checkState;
+
import java.util.EventListener;
+import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.HashMap;
import java.util.Set;
import java.util.WeakHashMap;
-import javax.swing.tree.ExpandVetoException;
-
import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
-import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper;
import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
-import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static com.google.common.base.Preconditions.*;
-
public class RpcProviderRegistryImpl implements //
RpcProviderRegistry, //
RouteChangePublisher<RpcContextIdentifier, InstanceIdentifier<?>> {
private final String name;
- private ListenerRegistry<GlobalRpcRegistrationListener> globalRpcListeners = ListenerRegistry.create();
+ private final ListenerRegistry<GlobalRpcRegistrationListener> globalRpcListeners = ListenerRegistry.create();
public String getName() {
return name;
@Override
public final <T extends RpcService> T getRpcService(Class<T> type) {
- @SuppressWarnings("unchecked")
T potentialProxy = (T) publicProxies.get(type);
if (potentialProxy != null) {
return potentialProxy;
potentialProxy = (T) publicProxies.get(type);
if (potentialProxy != null) {
- return (T) potentialProxy;
+ return potentialProxy;
}
T proxy = rpcFactory.getDirectProxyFor(type);
LOG.debug("Created {} as public proxy for {} in {}", proxy, type.getSimpleName(), this);
LOG.error("Unhandled exception during invoking listener {}", e);
}
}
-
+
}
- private void notifyListenersRoutedCreated(RpcRouter router) {
+ private void notifyListenersRoutedCreated(RpcRouter<?> router) {
for (ListenerRegistration<RouterInstantiationListener> listener : routerInstantiationListener) {
try {
public interface RouterInstantiationListener extends EventListener {
void onRpcRouterCreated(RpcRouter<?> router);
}
-
+
public ListenerRegistration<GlobalRpcRegistrationListener> registerGlobalRpcRegistrationListener(GlobalRpcRegistrationListener listener) {
return globalRpcListeners.register(listener);
}
public interface GlobalRpcRegistrationListener extends EventListener {
void onGlobalRpcRegistered(Class<? extends RpcService> cls);
void onGlobalRpcUnregistered(Class<? extends RpcService> cls);
-
+
}
private class RouteChangeForwarder<T extends RpcService> implements
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);
}
import org.opendaylight.controller.md.sal.common.api.data.DataModification;
import org.opendaylight.yangtools.concepts.Path;
-import com.google.common.util.concurrent.JdkFutureAdapters;
-
public final class DataModificationTracker<P extends Path<P>,D> {
-
ConcurrentMap<Object, DataModification<P,D>> trackedTransactions = new ConcurrentHashMap<>();
-
-
+
public void startTrackingModification(DataModification<P,D> modification) {
trackedTransactions.putIfAbsent(modification.getIdentifier(), modification);
-
-
}
-
+
public boolean containsIdentifier(Object identifier) {
return trackedTransactions.containsKey(identifier);
}
import org.junit.After;
import org.junit.Before;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
import org.opendaylight.controller.sal.core.api.data.DataStore;
import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
-import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
+import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
*/
package org.opendaylight.controller.sal.binding.test;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import javassist.ClassPool;
import org.junit.Before;
import org.junit.Test;
-
-import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*;
-
-import org.opendaylight.controller.sal.binding.api.NotificationListener;
import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
import org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator;
import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker;
import org.opendaylight.controller.sal.binding.test.mock.BarListener;
import org.opendaylight.controller.sal.binding.test.mock.BarUpdate;
-import org.opendaylight.controller.sal.binding.test.mock.CompositeListener;
import org.opendaylight.controller.sal.binding.test.mock.FlowDelete;
import org.opendaylight.controller.sal.binding.test.mock.FooListener;
import org.opendaylight.controller.sal.binding.test.mock.FooService;
import org.opendaylight.controller.sal.binding.test.mock.FooUpdate;
-import org.opendaylight.controller.sal.binding.test.mock.InheritedContextInput;
import org.opendaylight.controller.sal.binding.test.mock.ReferencableObject;
import org.opendaylight.controller.sal.binding.test.mock.ReferencableObjectKey;
import org.opendaylight.controller.sal.binding.test.mock.SimpleInput;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
-import static org.mockito.Mockito.*;
-
public class RuntimeCodeGeneratorTest {
private RuntimeCodeGenerator codeGenerator;
NotificationInvoker invokerFoo = invokerFactory.invokerFor(fooListener);
-
+
assertSame(fooListener,invokerFoo.getDelegate());
assertNotNull(invokerFoo.getSupportedNotifications());
assertEquals(1, invokerFoo.getSupportedNotifications().size());
import org.opendaylight.yangtools.yang.binding.Identifier;
public class ReferencableObjectKey implements Identifier<ReferencableObject> {
-
+ private static final long serialVersionUID = 1L;
final Integer value;
-
+
public ReferencableObjectKey(Integer _value) {
this.value = _value;
}
public String toString() {
return "ReferencableObjectKey [value=" + value + "]";
}
-
-
+
+
}
import javassist.ClassPool;
-import org.opendaylight.controller.sal.core.api.data.DataStore;
-import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
-import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
-import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
-
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
private ExecutorService executor;
private ClassPool classPool;
-
+
public boolean isStartWithParsedSchema() {
return startWithParsedSchema;
}
if(classPool == null) {
return CLASS_POOL;
}
-
+
return classPool;
}
*/
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 java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-
-
-
-
-
-
-
import org.junit.Test;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsActionCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.mpls.action._case.PopMplsActionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
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.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
import org.opendaylight.yangtools.yang.binding.DataObject;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
-import static org.junit.Assert.*;
-
public class DOMCodecBug01Test extends AbstractDataServiceTest {
private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
flow.setNode(NODE_REF);
InstructionsBuilder instructions = new InstructionsBuilder();
InstructionBuilder instruction = new InstructionBuilder();
-
+
instruction.setOrder(10);
ApplyActionsBuilder applyActions = new ApplyActionsBuilder();
List<Action> actionList = new ArrayList<>();
assertNotNull(ret);
assertEquals(TransactionStatus.COMMITED, ret.getResult());
}
-
+
private void createFlow2() throws Exception {
DataModificationTransaction modification = baDataService.beginTransaction();
long id = 123;
MatchBuilder match = new MatchBuilder();
match.setLayer4Match(new TcpMatchBuilder().build());
flow.setMatch(match.build());
-
+
path1 = InstanceIdentifier.builder(Flows.class).child(Flow.class, key).toInstance();
// DataObject cls = (DataObject) modification.readConfigurationData(path1);
modification.putConfigurationData(path1, flow.build());
*/
package org.opendaylight.controller.sal.binding.test.bugfix;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.Callable;
import javassist.ClassPool;
-import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
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.NodesBuilder;
+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.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
-import static org.junit.Assert.*;
-
public class DOMCodecBug02Test extends AbstractDataServiceTest {
private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
/**
* This test is ignored, till found out better way to test generation
* of classes without leaking of instances from previous run
- *
+ *
* @throws Exception
*/
-
+
+ @Override
public void setUp() {
ListeningExecutorService executor = MoreExecutors.sameThreadExecutor();
BindingBrokerTestFactory factory = new BindingBrokerTestFactory();
factory.setStartWithParsedSchema(getStartWithSchema());
testContext = factory.getTestContext();
testContext.start();
-
+
baDataService = testContext.getBindingDataBroker();
biDataService = testContext.getDomDataBroker();
dataStore = testContext.getDomDataStore();
mappingService = testContext.getBindingToDomMappingService();
};
-
+
@Test
public void testSchemaContextNotAvailable() throws Exception {
return transaction.commit();
}
});
-
-
+
+
RpcResult<TransactionStatus> result = future.get().get();
assertEquals(TransactionStatus.COMMITED, result.getResult());
-
+
Nodes nodes = checkForNodes();
assertNotNull(nodes);
return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
}
-
+
@Override
protected boolean getStartWithSchema() {
return false;
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.controller.sal.binding.test.bugfix;
-import java.util.Arrays;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
-import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActions;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActionsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionTypeBuilder;
+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.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType;
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.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import static org.junit.Assert.*;
-
public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataChangeListener {
private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
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();
-
+
private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = //
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
.toInstance();
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;
-
-
+
+
/**
* Test for Bug 148
- *
+ *
* @throws Exception
*/
@Test
public void testAugmentSerialization() throws Exception {
-
+
baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
-
+
NodeBuilder nodeBuilder = new NodeBuilder();
nodeBuilder.setId(new NodeId(NODE_ID));
nodeBuilder.setKey(NODE_KEY);
DataModificationTransaction transaction = baDataService.beginTransaction();
-
-
+
+
FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder();
fnub.setHardware("Hardware Foo");
fnub.setManufacturer("Manufacturer Foo");
nodeBuilder.addAugmentation(FlowCapableNode.class, fnu);
Node original = nodeBuilder.build();
transaction.putOperationalData(NODE_INSTANCE_ID_BA, original);
-
+
RpcResult<TransactionStatus> result = transaction.commit().get();
assertEquals(TransactionStatus.COMMITED, result.getResult());
-
+
assertNotNull(receivedChangeEvent);
-
+
verifyNodes((Nodes) receivedChangeEvent.getUpdatedOperationalSubtree(),original);
assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
Nodes nodes = checkForNodes();
verifyNodes(nodes,original);
-
+
testAddingNodeConnector();
testNodeRemove();
}
-
+
@Test
public void testAugmentNestedSerialization() throws Exception {
DataModificationTransaction transaction = baDataService.beginTransaction();
-
+
SupportedActionsBuilder actions = new SupportedActionsBuilder();
ActionTypeBuilder action = new ActionTypeBuilder();
action.setAction("foo-action");
action.setSupportState(SupportType.Native);
List<ActionType> actionTypes = Collections.singletonList(action.build());
actions.setActionType(actionTypes );
-
+
transaction.putOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BA, actions.build());
RpcResult<TransactionStatus> putResult = transaction.commit().get();
assertNotNull(putResult);
assertEquals(TransactionStatus.COMMITED, putResult.getResult());
SupportedActions readedTable = (SupportedActions) baDataService.readOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BA);
assertNotNull(readedTable);
-
+
CompositeNode biSupportedActions = biDataService.readOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BI);
assertNotNull(biSupportedActions);
-
+
}
private void testAddingNodeConnector() throws Exception {
-
+
NodeConnectorId ncId = new NodeConnectorId("openflow:1:bar");
NodeConnectorKey nodeKey = new NodeConnectorKey(ncId );
InstanceIdentifier<NodeConnector> ncInstanceId = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).child(NodeConnector.class, nodeKey).toInstance();
transaction.removeOperationalData(NODE_INSTANCE_ID_BA);
RpcResult<TransactionStatus> result = transaction.commit().get();
assertEquals(TransactionStatus.COMMITED, result.getResult());
-
+
Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
assertNull(node);
}
Node readedNode = nodes.getNode().get(0);
assertEquals(original.getId(), readedNode.getId());
assertEquals(original.getKey(), readedNode.getKey());
-
+
FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class);
FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class);
assertNotNull(fnu);
assertEquals(fnu.getDescription(), readedAugment.getDescription());
assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber());
-
+
}
private void assertBindingIndependentVersion(
private Nodes checkForNodes() {
return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
}
-
+
@Override
public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
receivedChangeEvent = change;
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.controller.sal.binding.test.bugfix;
-import java.util.Arrays;
+
+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.List;
import java.util.Map;
import org.junit.Test;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
-import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActions;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionTypeBuilder;
+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.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.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import static org.junit.Assert.*;
-
public class PutAugmentationTest extends AbstractDataServiceTest implements DataChangeListener {
private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
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
- *
+ *
* @throws Exception
*/
@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));
nodeBuilder.setKey(NODE_KEY);
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());
-
+
FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder();
fnub.setHardware("Hardware Foo");
fnub.setManufacturer("Manufacturer Foo");
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(NODE_KEY, augmentedNode.getKey());
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);
fnub.setDescription("Description Foo");
fnub.setSoftware("JUnit emulated");
FlowCapableNode fnu = fnub.build();
-
+
nodeBuilder.addAugmentation(FlowCapableNode.class, fnu);
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);
-
+
FlowCapableNodeConnectorBuilder fncb = new FlowCapableNodeConnectorBuilder();
fncb.setName("Baz");
nc.addAugmentation(FlowCapableNodeConnector.class, fncb.build());
-
+
DataModificationTransaction baseTransaction = baDataService.beginTransaction();
baseTransaction.putOperationalData(ncPath, nc.build());
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());
}
transaction.removeOperationalData(NODE_INSTANCE_ID_BA);
RpcResult<TransactionStatus> result = transaction.commit().get();
assertEquals(TransactionStatus.COMMITED, result.getResult());
-
+
Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
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());
Node readedNode = nodes.getNode().get(0);
assertEquals(original.getId(), readedNode.getId());
assertEquals(original.getKey(), readedNode.getKey());
-
+
FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class);
FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class);
assertNotNull(fnu);
assertEquals(fnu.getDescription(), readedAugment.getDescription());
assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber());
-
+
}
- 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);
}
private Nodes checkForNodes() {
return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
}
-
+
@Override
public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
- receivedChangeEvent = change;
+ lastReceivedChangeEvent = change;
}
}
import java.util.Collections;
import java.util.Map;
-import javax.management.Notification;
-
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
import org.opendaylight.controller.md.sal.common.api.data.DataReader;
import org.opendaylight.controller.sal.binding.api.mount.MountProviderInstance;
import org.opendaylight.controller.sal.binding.api.mount.MountProviderService;
import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
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.FlowKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatistics;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
-import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
-import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.MoreExecutors;
public class CrossBrokerMountPointTest {
assertNotNull(bindingMountPoint);
final BigInteger packetCount = BigInteger.valueOf(500L);
-
-
+
+
DataReader<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> simpleReader = new DataReader<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>() {
@Override
return null;
}
-
+
@Override
public CompositeNode readOperationalData(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier arg0) {
if (arg0.equals(GROUP_STATISTICS_ID_BI)) {
};
domMountPoint.registerOperationalReader(NODE_INSTANCE_ID_BI, simpleReader);
-
+
GroupStatistics data = (GroupStatistics) bindingMountPoint.readOperationalData(GROUP_STATISTICS_ID_BA);
assertNotNull(data);
assertEquals(packetCount,data.getPacketCount().getValue());
import static org.ops4j.pax.exam.CoreOptions.frameworkProperty;
import static org.ops4j.pax.exam.CoreOptions.junitBundles;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.repository;
-import static org.ops4j.pax.exam.CoreOptions.repositories;
import static org.ops4j.pax.exam.CoreOptions.systemProperty;
import org.ops4j.pax.exam.Option;
public static Option bindingAwareSalBundles() {
return new DefaultCompositeOption( //
mdSalCoreBundles(),
-
+
mavenBundle("org.javassist", "javassist").versionAsInProject(), // //
-
+
mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), // //
mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), // //
mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), // //
"binding-generator-spi").versionAsInProject(), //
mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(),
mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), // //
-
+
mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), //
mavenBundle(CONTROLLER, "sal-binding-api").versionAsInProject(), // //
mavenBundle(CONTROLLER, "sal-binding-config").versionAsInProject(), //
mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject(), // //
-
+
mavenBundle(CONTROLLER, "sal-broker-impl").versionAsInProject(), // //
mavenBundle(CONTROLLER, "sal-core-spi").versionAsInProject().update(), //
*/
package org.opendaylight.controller.test.sal.binding.it;
-import static org.ops4j.pax.exam.CoreOptions.*;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.*;
-
-import javax.inject.Inject;
-
import org.junit.runner.RunWith;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
-import org.ops4j.pax.exam.options.DefaultCompositeOption;
import org.ops4j.pax.exam.util.Filter;
-import org.ops4j.pax.exam.util.PathUtils;
import org.osgi.framework.BundleContext;
+import javax.inject.Inject;
+
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.baseModelBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.bindingAwareSalBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.configMinumumBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.flowCapableModelBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.junitAndMockitoBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.mdSalCoreBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
@RunWith(PaxExam.class)
public abstract class AbstractTest {
public static final String YANGTOOLS_MODELS = "org.opendaylight.yangtools.model";
@Inject
- @Filter(timeout=60*1000)
+ @Filter(timeout=120*1000)
BindingAwareBroker broker;
@Inject
import java.util.Collections;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.yangtools.yang.binding.RpcService;
import org.junit.Test;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
public class NoficationTest extends AbstractTest {
- private FlowListener listener1 = new FlowListener();
- private FlowListener listener2 = new FlowListener();
+ private final FlowListener listener1 = new FlowListener();
+ private final FlowListener listener2 = new FlowListener();
private Registration<NotificationListener> listener1Reg;
private Registration<NotificationListener> listener2Reg;
@Test
public void notificationTest() throws Exception {
/**
- *
+ *
* The registration of the Provider 1.
- *
+ *
*/
AbstractTestProvider provider1 = new AbstractTestProvider() {
@Override
assertNotNull(notifyProviderService);
/**
- *
+ *
* The registration of the Consumer 1. It retrieves Notification Service
* from MD-SAL and registers SalFlowListener as notification listener
- *
+ *
*/
BindingAwareConsumer consumer1 = new BindingAwareConsumer() {
@Override
/**
* Check that one notification was delivered and has correct cookie.
- *
+ *
*/
assertEquals(1, listener1.addedFlows.size());
assertEquals(0, listener1.addedFlows.get(0).getCookie().intValue());
* registered as notification listener.
*/
BindingAwareProvider provider = new BindingAwareProvider() {
-
+
@Override
public void onSessionInitiated(ProviderContext session) {
listener2Reg = session.getSALService(NotificationProviderService.class).registerNotificationListener(
listener2);
}
-
+
@Override
public void onSessionInitialized(ConsumerContext session) {
// TODO Auto-generated method stub
-
+
}
-
+
@Override
public Collection<? extends RpcService> getImplementations() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public Collection<? extends ProviderFunctionality> getFunctionality() {
// TODO Auto-generated method stub
return null;
}
-
+
};
// registerConsumer method calls onSessionInitialized method above
/**
* Check that 3 notification was delivered to both listeners (first one
* received 4 in total, second 3 in total).
- *
+ *
*/
assertEquals(4, listener1.addedFlows.size());
assertEquals(3, listener2.addedFlows.size());
/**
* The second listener is closed (unregistered)
- *
+ *
*/
listener2Reg.close();
/**
- *
+ *
* The notification 5 is published
*/
notifyProviderService.publish(flowAdded(10));
* Check that first consumer received 5 notifications in total, second
* consumer received only three. Last notification was never received by
* second consumer because its listener was unregistered.
- *
+ *
*/
assertEquals(5, listener1.addedFlows.size());
assertEquals(3, listener2.addedFlows.size());
/**
* Creates instance of the type FlowAdded. Only cookie value is set. It is
* used only for testing purpose.
- *
+ *
* @param i
* cookie value
* @return instance of the type FlowAdded
}
/**
- *
+ *
* Implements
* {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener
* SalFlowListener} and contains attributes which keep lists of objects of
@Override
public void onFlowRemoved(FlowRemoved notification) {
removedFlows.add(notification);
- };
+ };
@Override
public void onFlowUpdated(FlowUpdated notification) {
@Override
public void onSwitchFlowRemoved(SwitchFlowRemoved notification) {
// TODO Auto-generated method stub
-
+
}
@Override
public void onNodeErrorNotification(NodeErrorNotification notification) {
// TODO Auto-generated method stub
-
+
}
@Override
public void onNodeExperimenterErrorNotification(
NodeExperimenterErrorNotification notification) {
// TODO Auto-generated method stub
-
+
}
}
import static org.mockito.Mockito.verify;
import java.math.BigInteger;
-import java.util.concurrent.Future;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContext;
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.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
public class RoutedServiceTest extends AbstractTest {
/**
* Register provider 1 with first implementation of SalFlowService -
* service1
- *
+ *
*/
broker.registerProvider(provider1, getBundleContext());
assertNotNull("Registration should not be null", firstReg);
/**
* Register provider 2 with first implementation of SalFlowService -
* service2
- *
+ *
*/
broker.registerProvider(provider2, getBundleContext());
assertNotNull("Registration should not be null", firstReg);
/**
* Consumer creates addFlow message for node one and sends it to the
* MD-SAL
- *
+ *
*/
AddFlowInput addFlowFirstMessage = createSampleAddFlow(nodeOne, 1);
consumerService.addFlow(addFlowFirstMessage);
/**
* Verifies that implementation of the first provider received the same
* message from MD-SAL.
- *
+ *
*/
verify(salFlowService1).addFlow(addFlowFirstMessage);
/**
* Verifies that second instance was not invoked with first message
- *
+ *
*/
verify(salFlowService2, times(0)).addFlow(addFlowFirstMessage);
/**
* Provider 2 registers path of node 2
- *
+ *
*/
NodeRef nodeTwo = createNodeRef("foo:node:2");
secondReg.registerPath(NodeContext.class, nodeTwo.getValue());
/**
* Verifies that second instance was invoked 3 times with second message
* and first instance wasn't invoked.
- *
+ *
*/
verify(salFlowService2, times(3)).addFlow(AddFlowSecondMessage);
verify(salFlowService1, times(0)).addFlow(AddFlowSecondMessage);
/**
* Unregisteration of the path for the node one in the first provider
- *
+ *
*/
firstReg.unregisterPath(NodeContext.class, nodeOne.getValue());
/**
* Provider 2 registers path of node 1
- *
+ *
*/
secondReg.registerPath(NodeContext.class, nodeOne.getValue());
/**
* A consumer sends third message to node 1
- *
+ *
*/
AddFlowInput AddFlowThirdMessage = createSampleAddFlow(nodeOne, 3);
consumerService.addFlow(AddFlowThirdMessage);
/**
* Returns node reference from string which represents path
- *
+ *
* @param string
* string with key(path)
* @return instance of the type NodeRef
/**
* Creates flow AddFlowInput for which only node and cookie are set
- *
+ *
* @param node
* NodeRef value
* @param cookie
package org.opendaylight.controller.md.sal.binding.util;
import java.util.concurrent.Future;
-import java.util.zip.Checksum;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
import org.opendaylight.controller.sal.binding.api.NotificationListener;
import org.opendaylight.controller.sal.binding.api.NotificationService;
import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
-import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
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.binding.api.mount.MountInstance;
import org.opendaylight.controller.sal.common.DataStoreIdentifier;
-import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.DataObject;
protected final D getDataBroker() {
return dataBroker;
}
-
+
protected final R getRpcRegistryChecked() {
Preconditions.checkState(rpcRegistry != null,"Rpc Registry is not available.");
return rpcRegistry;
Preconditions.checkState(dataBroker != null, "Data Broker is not available");
return dataBroker;
}
-
+
protected AbstractBindingSalConsumerInstance(R rpcRegistry, N notificationBroker, D dataBroker) {
this.rpcRegistry = rpcRegistry;
this.dataBroker = dataBroker;
}
+ @Override
public <T extends RpcService> T getRpcService(Class<T> module) {
return getRpcRegistryChecked().getRpcService(module);
}
+ @Override
@Deprecated
public <T extends Notification> void addNotificationListener(Class<T> notificationType,
NotificationListener<T> listener) {
getNotificationBrokerChecked().addNotificationListener(notificationType, listener);
}
+ @Override
@Deprecated
public void addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
getNotificationBrokerChecked().addNotificationListener(listener);
}
+ @Override
@Deprecated
public void removeNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
getNotificationBrokerChecked().removeNotificationListener(listener);
}
+ @Override
@Deprecated
public <T extends Notification> void removeNotificationListener(Class<T> notificationType,
NotificationListener<T> listener) {
getNotificationBrokerChecked().removeNotificationListener(notificationType, listener);
}
+ @Override
public <T extends Notification> Registration<NotificationListener<T>> registerNotificationListener(
Class<T> notificationType, NotificationListener<T> listener) {
return getNotificationBrokerChecked().registerNotificationListener(notificationType, listener);
}
+ @Override
public Registration<org.opendaylight.yangtools.yang.binding.NotificationListener> registerNotificationListener(
org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
return getNotificationBrokerChecked().registerNotificationListener(listener);
}
+ @Override
@Deprecated
public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
return getDataBrokerChecked().getData(store, rootType);
}
+ @Override
@Deprecated
public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
return getDataBrokerChecked().getData(store, filter);
}
+ @Override
@Deprecated
public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
return getDataBrokerChecked().getCandidateData(store, rootType);
}
+ @Override
@Deprecated
public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
return getDataBrokerChecked().getCandidateData(store, filter);
}
+ @Override
@Deprecated
public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
return getDataBrokerChecked().editCandidateData(store, changeSet);
}
+ @Override
@Deprecated
public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
return getDataBrokerChecked().commit(store);
}
+ @Override
@Deprecated
public DataObject getData(InstanceIdentifier<? extends DataObject> data) {
return getDataBrokerChecked().getData(data);
}
+ @Override
@Deprecated
public DataObject getConfigurationData(InstanceIdentifier<?> data) {
return getDataBrokerChecked().getConfigurationData(data);
}
+ @Override
public DataModificationTransaction beginTransaction() {
return getDataBrokerChecked().beginTransaction();
}
+ @Override
@Deprecated
public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
getDataBrokerChecked().registerChangeListener(path, changeListener);
}
+ @Override
@Deprecated
public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path,
DataChangeListener changeListener) {
getDataBrokerChecked().unregisterChangeListener(path, changeListener);
}
+ @Override
@Deprecated
public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
return getDataBrokerChecked().readConfigurationData(path);
}
+ @Override
public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
return getDataBrokerChecked().readOperationalData(path);
}
+ @Override
@Deprecated
public ListenerRegistration<DataChangeListener> registerDataChangeListener(
InstanceIdentifier<? extends DataObject> path, DataChangeListener listener) {
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
-import org.opendaylight.controller.sal.binding.api.mount.MountProviderInstance;
import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
L listener) {
return getRpcRegistryChecked().registerRouteChangeListener(listener);
}
-
+
@Override
public ListenerRegistration<NotificationInterestListener> registerInterestListener(
NotificationInterestListener interestListener) {
*/
package org.opendaylight.controller.md.sal.binding.util;
-import java.awt.image.SinglePixelPackedSampleModel;
+import static com.google.common.base.Preconditions.checkNotNull;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
-import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
-import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
import org.opendaylight.controller.sal.binding.api.BindingAwareService;
import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.RpcService;
-import static com.google.common.base.Preconditions.*;
-
import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.MutableClassToInstanceMap;
checkNotNull(serviceProvider,"Service map should not be null");
return new SingleConsumerContextImpl(serviceProvider);
}
-
+
public static ProviderContext createProviderContext(BindingAwareProvider provider,
ClassToInstanceMap<BindingAwareService> serviceProvider) {
checkNotNull(provider,"Provider should not be null");
consumer.onSessionInitialized(context);
return context;
}
-
+
public static ProviderContext createProviderContextAndInitialize(BindingAwareProvider provider,
ClassToInstanceMap<BindingAwareService> serviceProvider) {
ProviderContext context = createProviderContext(provider, serviceProvider);
// FIXME: Create Proxy
return instance;
}
-
+
private static class SingleConsumerContextImpl implements ConsumerContext, AutoCloseable {
-
+
private ClassToInstanceMap<BindingAwareService> alreadyRetrievedServices;
private ClassToInstanceMap<BindingAwareService> serviceProvider;
public final <T extends RpcService> T getRpcService(Class<T> module) {
return getSALService(RpcConsumerRegistry.class).getRpcService(module);
}
-
+
@Override
public final <T extends BindingAwareService> T getSALService(Class<T> service) {
checkNotNull(service,"Service class should not be null.");
}
return tryToRetrieveSalService(service);
}
-
+
private synchronized <T extends BindingAwareService> T tryToRetrieveSalService(Class<T> service) {
final T potential = alreadyRetrievedServices.getInstance(service);
if(potential != null) {
alreadyRetrievedServices.put(service, retrieved);
return retrieved;
}
-
+
@Override
public final void close() throws Exception {
alreadyRetrievedServices = null;
serviceProvider = null;
}
}
-
+
private static class SingleProviderContextImpl extends SingleConsumerContextImpl implements ProviderContext {
public SingleProviderContextImpl(ClassToInstanceMap<BindingAwareService> serviceProvider) {
super(serviceProvider);
}
-
+
@Override
public <L extends RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
L listener) {
return getSALService(RpcProviderRegistry.class).registerRouteChangeListener(listener);
}
-
+
@Override
public <T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> type,
T implementation) throws IllegalStateException {
return getSALService(RpcProviderRegistry.class).addRoutedRpcImplementation(type, implementation);
}
-
+
@Override
public <T extends RpcService> RpcRegistration<T> addRpcImplementation(Class<T> type, T implementation)
throws IllegalStateException {
return getSALService(RpcProviderRegistry.class).addRpcImplementation(type, implementation);
}
-
+
@Deprecated
@Override
public void registerFunctionality(ProviderFunctionality functionality) {
// NOOP
}
-
+
@Deprecated
@Override
public void unregisterFunctionality(ProviderFunctionality functionality) {
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,
}
import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
// import org.opendaylight.yangtools.concepts.Path;
-import org.opendaylight.yangtools.concepts.Registration;
-
public interface DataChangePublisher<P/* extends Path<P> */,D, L extends DataChangeListener<P,D>> {
ListenerRegistration<L> registerDataChangeListener(P path, L listener);
*/
package org.opendaylight.controller.md.sal.common.api.data;
-import java.util.Map;
-import java.util.Set;
import java.util.concurrent.Future;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
-// import org.opendaylight.yangtools.concepts.Path;
import org.opendaylight.yangtools.yang.common.RpcResult;
+//FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
+//import org.opendaylight.yangtools.concepts.Path;
public interface DataModification<P/* extends Path<P> */, D> extends DataChange<P, D>, DataReader<P, D> {
/**
* Returns transaction identifier
- *
+ *
* @return Transaction identifier
*/
Object getIdentifier();
TransactionStatus getStatus();
/**
- *
+ *
* @deprecated Use {@link #putOperationalData(Object, Object)} instead.
- *
+ *
* @param path
* @param data
*/
/**
* @deprecated Use {@link #removeOperationalData(Object)}
- *
+ *
* @param path
*/
@Deprecated
/**
* Initiates a two-phase commit of modification.
- *
+ *
* <p>
* The successful commit changes the state of the system and may affect
* several components.
- *
+ *
* <p>
* The effects of successful commit of data are described in the
* specifications and YANG models describing the Provider components of
* controller. It is assumed that Consumer has an understanding of this
* changes.
- *
- *
+ *
+ *
* @see DataCommitHandler for further information how two-phase commit is
* processed.
* @param store
*/
package org.opendaylight.controller.md.sal.common.impl;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import java.util.Collections;
import java.util.EventListener;
import java.util.HashSet;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import static com.google.common.base.Preconditions.*;
import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
return unmodifiableView;
}
-
+
public ListenerRegistration<T> register(T listener) {
checkNotNull(listener, "Listener should not be null.");
ListenerRegistrationImpl<T> ret = new ListenerRegistrationImpl<T>(listener);
listeners.add(ret);
return ret;
}
-
-
+
+
@SuppressWarnings("rawtypes")
private void remove(ListenerRegistrationImpl registration) {
listeners.remove(registration);
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
- for (listenerSet : listeners) {\r
- val updatedConfiguration = dataBroker.readConfigurationData(listenerSet.path);\r
- val updatedOperational = dataBroker.readOperationalData(listenerSet.path);\r
-\r
- val changeEvent = new DataChangeEventImpl(transaction, listenerSet.initialConfigurationState,\r
- listenerSet.initialOperationalState, updatedOperational, updatedConfiguration);\r
- for (listener : listenerSet.listeners) {\r
- try {\r
- listener.instance.onDataChanged(changeEvent);\r
-\r
- } catch (Exception e) {\r
- e.printStackTrace();\r
- }\r
- }\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);
+ }
+}
package org.opendaylight.controller.md.sal.common.impl.util;
import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
private final ReentrantReadWriteLock delegateLock = new ReentrantReadWriteLock();
private final ReadLock delegateReadLock = delegateLock.readLock();
private final WriteLock delegateWriteLock = delegateLock.writeLock();
-
-
+
+
protected Lock getDelegateReadLock() {
return delegateReadLock;
}
}
/**
- *
+ *
* @param newDelegate
* @return oldDelegate
*/
delegateWriteLock.unlock();
}
}
-
-
+
+
protected void onDelegateChanged(T oldDelegate, T newDelegate) {
// NOOP in abstract calss;
}
package org.opendaylight.controller.sal.common.util;
import java.io.Serializable;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.common.RpcError;
import com.google.common.collect.ImmutableList;
public class Rpcs {
-
+
public static <T> RpcResult<T> getRpcResult(boolean successful) {
RpcResult<T> ret = new RpcResultTO<T>(successful, null, ImmutableList.<RpcError>of());
return ret;
}
-
+
public static <T> RpcResult<T> getRpcResult(boolean successful, T result,
Collection<RpcError> errors) {
RpcResult<T> ret = new RpcResultTO<T>(successful, result, errors);
public static <T> RpcResult<T> getRpcResult(boolean successful, Collection<RpcError> errors) {
return new RpcResultTO<T>(successful, null, errors);
}
-
- private static class RpcResultTO<T> implements RpcResult<T>, Serializable, Immutable {
+ private static class RpcResultTO<T> implements RpcResult<T>, Serializable, Immutable {
+ private static final long serialVersionUID = 1L;
private final Collection<RpcError> errors;
private final T result;
private final boolean successful;
import java.util.Collection;
import java.util.Collections;
-import javax.naming.Context;
-
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
broker.registerProvider(this, context);
return broker;
}
-
+
return null;
}
-
+
@Override
public void modifiedService(ServiceReference<Broker> reference, Broker service) {
// NOOP
}
-
+
@Override
public void removedService(ServiceReference<Broker> reference, Broker service) {
stopImpl(context);
}
-
+
}
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.
package org.opendaylight.controller.sal.core.api.data;
import java.util.EventListener;
-import java.util.Map;
-import java.util.Set;
import java.util.concurrent.Future;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
/**
* Returns transaction identifier
- *
+ *
* @return Transaction identifier
*/
+ @Override
Object getIdentifier();
-
+
+ @Override
TransactionStatus getStatus();
-
+
/**
* Commits transaction to be stored in global data repository.
- *
- *
- * @return Future object which returns RpcResult with TransactionStatus
+ *
+ *
+ * @return Future object which returns RpcResult with TransactionStatus
* when transaction is processed by store.
*/
+ @Override
Future<RpcResult<TransactionStatus>> commit();
-
+
ListenerRegistration<DataTransactionListener> registerListener(DataTransactionListener listener);
-
-
+
public interface DataTransactionListener extends EventListener {
-
void onStatusUpdated(DataModificationTransaction transaction,TransactionStatus status);
-
}
-
-
-
}
import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.controller.sal.core.api.data.DataProviderService;
import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
-import com.google.common.base.Optional;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
public interface MountProvisionInstance extends //
<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 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 org.opendaylight.controller.sal.core.api.BrokerService;
import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.BrokerService;
import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;
import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
private static Logger log = LoggerFactory
.getLogger(NotificationModule.class);
- private Multimap<QName, NotificationListener> listeners = HashMultimap
+ private final Multimap<QName, NotificationListener> listeners = HashMultimap
.create();
private static final Set<Class<? extends BrokerService>> PROVIDED_SERVICE_TYPE = ImmutableSet
private class NotificationConsumerSessionImpl implements
NotificationService {
- private Multimap<QName, NotificationListener> consumerListeners = HashMultimap
+ private final Multimap<QName, NotificationListener> consumerListeners = HashMultimap
.create();
private boolean closed = false;
+ @Override
public Registration<NotificationListener> addNotificationListener(QName notification,
NotificationListener listener) {
checkSessionState();
package org.opendaylight.controller.sal.dom.broker.impl;
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 org.opendaylight.controller.sal.core.api.BrokerService;
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;
-import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
-import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
-import org.opendaylight.controller.sal.core.api.notify.NotificationService;
-import org.opendaylight.controller.sal.core.spi.BrokerModule;
import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
import org.opendaylight.yangtools.concepts.Registration;
import org.slf4j.LoggerFactory;
import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
public class NotificationRouterImpl implements NotificationRouter {
private static Logger log = LoggerFactory.getLogger(NotificationRouterImpl.class);
- private Multimap<QName, Registration<NotificationListener>> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.<QName, Registration<NotificationListener>>create());
+ private final Multimap<QName, Registration<NotificationListener>> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.<QName, Registration<NotificationListener>>create());
// private Registration<NotificationListener> defaultListener;
-
+
private void sendNotification(CompositeNode notification) {
final QName type = notification.getNodeType();
final Collection<Registration<NotificationListener>> toNotify = listeners.get(type);
public void publish(CompositeNode notification) {
sendNotification(notification);
}
-
+
@Override
public Registration<NotificationListener> addNotificationListener(QName notification, NotificationListener listener) {
ListenerRegistration ret = new ListenerRegistration(notification, listener);
*/
package org.opendaylight.controller.sal.dom.broker.impl;
+import static com.google.common.base.Preconditions.checkState;
+
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Map.Entry;
import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification;
import org.opendaylight.controller.md.sal.common.impl.util.AbstractLockableDelegator;
import org.opendaylight.controller.sal.core.api.data.DataStore;
+import org.opendaylight.controller.sal.dom.broker.util.YangDataOperations;
import org.opendaylight.controller.sal.dom.broker.util.YangSchemaUtils;
-import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
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.impl.CompositeNodeTOImpl;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.controller.sal.dom.broker.util.YangDataOperations;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
-
-import static com.google.common.base.Preconditions.*;
+import com.google.common.collect.ImmutableSet;
public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataStore> implements //
DataStore, //
SchemaServiceListener, //
+ SchemaContextListener, //
AutoCloseable {
private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class);
private SchemaContext schema = null;
private boolean validationEnabled = false;
- private DataReader<InstanceIdentifier, CompositeNode> reader = new MergeFirstLevelReader();
+ private final DataReader<InstanceIdentifier, CompositeNode> reader = new MergeFirstLevelReader();
@Override
public boolean containsConfigurationPath(InstanceIdentifier path) {
private NormalizedDataModification prepareMergedTransaction(
DataModification<InstanceIdentifier, CompositeNode> original) {
- // NOOP for now
NormalizedDataModification normalized = new NormalizedDataModification(original);
for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
normalized.putConfigurationData(entry.getKey(), entry.getValue());
normalized.putOperationalData(entry.getKey(), entry.getValue());
}
for (InstanceIdentifier entry : original.getRemovedConfigurationData()) {
- normalized.removeConfigurationData(entry);
+ normalized.deepRemoveConfigurationData(entry);
}
for (InstanceIdentifier entry : original.getRemovedOperationalData()) {
- normalized.removeOperationalData(entry);
+ normalized.deepRemoveOperationalData(entry);
}
return normalized;
}
+ private Iterable<InstanceIdentifier> getConfigurationSubpaths(InstanceIdentifier entry) {
+ // FIXME: This should be replaced by index
+ Iterable<InstanceIdentifier> paths = getStoredConfigurationPaths();
+
+ return getChildrenPaths(entry, paths);
+
+ }
+
+ public Iterable<InstanceIdentifier> getOperationalSubpaths(InstanceIdentifier entry) {
+ // FIXME: This should be indexed
+ Iterable<InstanceIdentifier> paths = getStoredOperationalPaths();
+
+ return getChildrenPaths(entry, paths);
+ }
+
+ private static final Iterable<InstanceIdentifier> getChildrenPaths(InstanceIdentifier entry,
+ Iterable<InstanceIdentifier> paths) {
+ ImmutableSet.Builder<InstanceIdentifier> children = ImmutableSet.builder();
+ for (InstanceIdentifier potential : paths) {
+ if (entry.contains(potential)) {
+ children.add(entry);
+ }
+ }
+ return children.build();
+ }
+
private final Comparator<Entry<InstanceIdentifier, CompositeNode>> preparationComparator = new Comparator<Entry<InstanceIdentifier, CompositeNode>>() {
@Override
public int compare(Entry<InstanceIdentifier, CompositeNode> o1, Entry<InstanceIdentifier, CompositeNode> o2) {
private class NormalizedDataModification extends AbstractDataModification<InstanceIdentifier, CompositeNode> {
- private Object identifier;
+ private final Object identifier;
private TransactionStatus status;
public NormalizedDataModification(DataModification<InstanceIdentifier, CompositeNode> original) {
status = TransactionStatus.NEW;
}
+ /**
+ *
+ * Ensures all subpaths are removed - this currently does slow lookup in
+ * all keys.
+ *
+ * @param entry
+ */
+ public void deepRemoveOperationalData(InstanceIdentifier entry) {
+ Iterable<InstanceIdentifier> paths = getOperationalSubpaths(entry);
+ removeOperationalData(entry);
+ for (InstanceIdentifier potential : paths) {
+ removeOperationalData(potential);
+ }
+ }
+
+ public void deepRemoveConfigurationData(InstanceIdentifier entry) {
+ Iterable<InstanceIdentifier> paths = getConfigurationSubpaths(entry);
+ removeConfigurationData(entry);
+ for (InstanceIdentifier potential : paths) {
+ removeConfigurationData(potential);
+ }
+ }
+
@Override
public Object getIdentifier() {
return this.identifier;
*/
package org.opendaylight.controller.sal.dom.broker.osgi;
-import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
public class MountProviderServiceProxy extends AbstractBrokerServiceProxy<MountProvisionService> implements MountProvisionService{
-
+
public MountProviderServiceProxy(ServiceReference<MountProvisionService> ref, MountProvisionService delegate) {
super(ref, delegate);
}
+ @Override
public MountProvisionInstance getMountPoint(InstanceIdentifier path) {
return getDelegate().getMountPoint(path);
}
+ @Override
public MountProvisionInstance createMountPoint(InstanceIdentifier path) {
return getDelegate().createMountPoint(path);
}
+ @Override
public MountProvisionInstance createOrGetMountPoint(InstanceIdentifier path) {
return getDelegate().createOrGetMountPoint(path);
}
-
+
@Override
public ListenerRegistration<MountProvisionListener> registerProvisionListener(MountProvisionListener listener) {
return getDelegate().registerProvisionListener(listener);
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);
+ }
}
import java.util.Set;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
-import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@Override
public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation);
-
+
@Override
public RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation)
throws IllegalArgumentException;
-
+
@Override
public Set<QName> getSupportedRpcs();
-
+
@Override
public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input);
}
*/
package org.opendaylight.controller.config.yang.md.sal.connector.netconf;
-import com.google.common.net.InetAddresses;
+import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkCondition;
+import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkNotNull;
import io.netty.channel.EventLoopGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.client.NetconfSshClientDispatcher;
import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
-import java.io.InputStream;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkCondition;
-import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkNotNull;
+import com.google.common.net.InetAddresses;
/**
-*
-*/
+ *
+ */
public final class NetconfConnectorModule extends org.opendaylight.controller.config.yang.md.sal.connector.netconf.AbstractNetconfConnectorModule
{
private static final Logger logger = LoggerFactory.getLogger(NetconfConnectorModule.class);
@Override
public java.lang.AutoCloseable createInstance() {
-
+
getDomRegistryDependency();
NetconfDevice device = new NetconfDevice(getIdentifier().getInstanceName());
String addressValue = getAddress();
} else {
addressValue = getAddress().getIpv6Address().getValue();
}
- */
+ */
double sleepFactor = 1.0;
int minSleep = 1000;
Long maxSleep = null;
Long deadline = null;
ReconnectStrategy strategy = new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, getBetweenAttemptsTimeoutMillis(),
minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
-
+
device.setReconnectStrategy(strategy);
-
+
InetAddress addr = InetAddresses.forString(addressValue);
InetSocketAddress socketAddress = new InetSocketAddress(addr , getPort().intValue());
-
+
device.setProcessingExecutor(getGlobalProcessingExecutor());
-
+
device.setSocketAddress(socketAddress);
device.setEventExecutor(getEventExecutorDependency());
device.setDispatcher(createDispatcher(clientConnectionTimeoutMillis));
device.setSchemaSourceProvider(getGlobalNetconfSchemaProvider(bundleContext));
-
+
getDomRegistryDependency().registerProvider(device, bundleContext);
device.start();
return device;
private ExecutorService getGlobalProcessingExecutor() {
if(GLOBAL_PROCESSING_EXECUTOR == null) {
-
+
GLOBAL_PROCESSING_EXECUTOR = Executors.newCachedThreadPool();
-
+
}
return GLOBAL_PROCESSING_EXECUTOR;
}
private synchronized AbstractCachingSchemaSourceProvider<String, InputStream> getGlobalNetconfSchemaProvider(BundleContext bundleContext) {
if(GLOBAL_NETCONF_SOURCE_PROVIDER == null) {
String storageFile = "cache/schema";
-// File directory = bundleContext.getDataFile(storageFile);
- File directory = new File("cache/schema");
+ // File directory = bundleContext.getDataFile(storageFile);
+ File directory = new File(storageFile);
SchemaSourceProvider<String> defaultProvider = SchemaSourceProviders.noopProvider();
GLOBAL_NETCONF_SOURCE_PROVIDER = FilesystemSchemaCachingProvider.createFromStringSourceProvider(defaultProvider, directory);
}
checkState(schemaSourceProvider != null, "Schema Source Provider must be set.")
checkState(eventExecutor != null, "Event executor must be set.");
- val listener = new NetconfDeviceListener(this, eventExecutor);
+ val listener = new NetconfDeviceListener(this);
val task = startClientTask(dispatcher, listener)
if (mountInstance != null) {
commitHandlerReg = mountInstance.registerCommitHandler(ROOT_PATH, this)
*/
package org.opendaylight.controller.sal.connect.netconf;
-import com.google.common.base.Objects;
-
-import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Promise;
-
-import java.util.List;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.locks.ReentrantLock;
-
-import org.eclipse.xtext.xbase.lib.Exceptions;
-import org.eclipse.xtext.xbase.lib.Functions.Function0;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.AbstractNetconfClientNotifySessionListener;
import org.opendaylight.controller.netconf.client.NetconfClientSession;
-import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
-import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
-import org.opendaylight.controller.sal.connect.netconf.NetconfMapping;
import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.Node;
-import org.w3c.dom.Document;
-
-@SuppressWarnings("all")
-class NetconfDeviceListener extends NetconfClientSessionListener {
- private final NetconfDevice device;
- private final EventExecutor eventExecutor;
-
- public NetconfDeviceListener(final NetconfDevice device, final EventExecutor eventExecutor) {
- this.device = device;
- this.eventExecutor = eventExecutor;
- }
- private Promise<NetconfMessage> messagePromise;
- private ConcurrentMap<String, Promise<NetconfMessage>> promisedMessages;
+import com.google.common.base.Preconditions;
- private final ReentrantLock promiseLock = new ReentrantLock();
+class NetconfDeviceListener extends AbstractNetconfClientNotifySessionListener {
+ private final NetconfDevice device;
- public void onMessage(final NetconfClientSession session, final NetconfMessage message) {
- if (isNotification(message)) {
- this.onNotification(session, message);
- } else {
- try {
- this.promiseLock.lock();
- boolean _notEquals = (!Objects.equal(this.messagePromise, null));
- if (_notEquals) {
- this.device.logger.debug("Setting promised reply {} with message {}", this.messagePromise, message);
- this.messagePromise.setSuccess(message);
- this.messagePromise = null;
- }
- } finally {
- this.promiseLock.unlock();
- }
- }
+ public NetconfDeviceListener(final NetconfDevice device) {
+ this.device = Preconditions.checkNotNull(device);
}
/**
* NetconfClientSessionListener#onMessage(NetconfClientSession,
* NetconfMessage)}
*/
+ @Override
public void onNotification(final NetconfClientSession session, final NetconfMessage message) {
this.device.logger.debug("Received NETCONF notification.", message);
CompositeNode domNotification = null;
}
}
}
-
- private static CompositeNode getNotificationBody(final CompositeNode node) {
- List<Node<? extends Object>> _children = node.getChildren();
- for (final Node<? extends Object> child : _children) {
- if ((child instanceof CompositeNode)) {
- return ((CompositeNode) child);
- }
- }
- return null;
- }
-
- public NetconfMessage getLastMessage(final int attempts, final int attemptMsDelay) throws InterruptedException {
- final Promise<NetconfMessage> promise = this.promiseReply();
- this.device.logger.debug("Waiting for reply {}", promise);
- int _plus = (attempts * attemptMsDelay);
- final boolean messageAvailable = promise.await(_plus);
- if (messageAvailable) {
- try {
- try {
- return promise.get();
- } catch (Throwable _e) {
- throw Exceptions.sneakyThrow(_e);
- }
- } catch (final Throwable _t) {
- if (_t instanceof ExecutionException) {
- final ExecutionException e = (ExecutionException) _t;
- IllegalStateException _illegalStateException = new IllegalStateException(e);
- throw _illegalStateException;
- } else {
- throw Exceptions.sneakyThrow(_t);
- }
- }
- }
- String _plus_1 = ("Unsuccessful after " + Integer.valueOf(attempts));
- String _plus_2 = (_plus_1 + " attempts.");
- IllegalStateException _illegalStateException_1 = new IllegalStateException(_plus_2);
- throw _illegalStateException_1;
- }
-
- public synchronized Promise<NetconfMessage> promiseReply() {
- this.device.logger.debug("Promising reply.");
- this.promiseLock.lock();
- try {
- boolean _equals = Objects.equal(this.messagePromise, null);
- if (_equals) {
- Promise<NetconfMessage> _newPromise = this.eventExecutor.<NetconfMessage> newPromise();
- this.messagePromise = _newPromise;
- return this.messagePromise;
- }
- return this.messagePromise;
- } finally {
- this.promiseLock.unlock();
- }
- }
-
- public boolean isNotification(final NetconfMessage message) {
- Document _document = message.getDocument();
- final XmlElement xmle = XmlElement.fromDomDocument(_document);
- String _name = xmle.getName();
- return XmlNetconfConstants.NOTIFICATION_ELEMENT_NAME.equals(_name);
- }
}
*/
package org.opendaylight.controller.sal.connect.netconf;
+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;
+
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Set;
-import org.eclipse.xtext.xbase.lib.IterableExtensions;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
-import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.*;
-
public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransaction<InstanceIdentifier, CompositeNode> {
- private NetconfDevice device;
+ private final NetconfDevice device;
private final DataModification<InstanceIdentifier, CompositeNode> modification;
- private boolean candidateSupported = true;
+ private final boolean candidateSupported = true;
public NetconfDeviceTwoPhaseCommitTransaction(NetconfDevice device,
DataModification<InstanceIdentifier, CompositeNode> modification) {
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) {
CompositeNodeBuilder<ImmutableCompositeNode> builder = configurationRpcBuilder();
builder.setQName(NETCONF_EDIT_CONFIG_QNAME);
builder.add(editStructure);
-
+
RpcResult<CompositeNode> rpcResult = device.invokeRpc(NETCONF_EDIT_CONFIG_QNAME, builder.toInstance());
Preconditions.checkState(rpcResult.isSuccessful(),"Rpc Result was unsuccessful");
-
+
}
private CompositeNodeBuilder<ImmutableCompositeNode> configurationRpcBuilder() {
CompositeNodeBuilder<ImmutableCompositeNode> ret = ImmutableCompositeNode.builder();
-
+
Node<?> targetNode;
if(candidateSupported) {
targetNode = ImmutableCompositeNode.create(NETCONF_CANDIDATE_QNAME, ImmutableList.<Node<?>>of());
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);
for (Entry<QName, Object> entry : predicates.entrySet()) {
builder.addLeaf(entry.getKey(), entry.getValue());
}
-
+
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();
builder.add(child);
}
}
-
+
}
} else {
builder.add(previous);
}
@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());
*/
package org.opendaylight.controller.sal.connect.netconf
-import org.opendaylight.controller.netconf.api.NetconfMessage
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.common.RpcResult
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import com.google.common.base.Optional
+import com.google.common.base.Preconditions
+import com.google.common.collect.ImmutableList
import java.net.URI
-import java.util.Collections
-import org.opendaylight.yangtools.yang.data.api.Node
-import org.opendaylight.yangtools.yang.data.impl.NodeUtils
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
import java.util.ArrayList
-import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import java.util.Collections
+import java.util.List
+import java.util.Set
import java.util.concurrent.atomic.AtomicInteger
-import org.w3c.dom.Document
-import org.w3c.dom.Element
import org.opendaylight.controller.sal.common.util.Rpcs
-import java.util.List
-import com.google.common.collect.ImmutableList
-import org.opendaylight.yangtools.yang.data.api.SimpleNode
+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.impl.CompositeNodeTOImpl
import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode
-import com.google.common.base.Preconditions
-import com.google.common.base.Optional
-import org.opendaylight.yangtools.yang.model.api.SchemaContext
+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 java.util.Set
+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);
}
import java.util.Set;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
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.model.util.repo.SchemaSourceProvider;
import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
class NetconfRemoteSchemaSourceProvider implements SchemaSourceProvider<String> {
*/
package org.opendaylight.controller.sal.connect.netconf;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.StringBufferInputStream;
-import java.io.StringReader;
import org.opendaylight.yangtools.concepts.Delegator;
import org.opendaylight.yangtools.yang.common.QName;
+import com.google.common.base.Charsets;
+
/**
- *
+ *
*
*/
public class YangModelInputStreamAdapter extends InputStream implements Delegator<InputStream> {
final String source;
final QName moduleIdentifier;
final InputStream delegate;
-
-
-
+
private YangModelInputStreamAdapter(String source, QName moduleIdentifier, InputStream delegate) {
super();
this.source = source;
this.delegate = delegate;
}
+ @Override
public int read() throws IOException {
return delegate.read();
}
+ @Override
public int hashCode() {
return delegate.hashCode();
}
+ @Override
public int read(byte[] b) throws IOException {
return delegate.read(b);
}
+ @Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
+ @Override
public int read(byte[] b, int off, int len) throws IOException {
return delegate.read(b, off, len);
}
+ @Override
public long skip(long n) throws IOException {
return delegate.skip(n);
}
+ @Override
public int available() throws IOException {
return delegate.available();
}
+ @Override
public void close() throws IOException {
delegate.close();
}
+ @Override
public void mark(int readlimit) {
delegate.mark(readlimit);
}
+ @Override
public void reset() throws IOException {
delegate.reset();
}
+ @Override
public boolean markSupported() {
return delegate.markSupported();
}
}
public static YangModelInputStreamAdapter create(QName name, String module) {
- InputStream stringInput = new StringBufferInputStream(module);
- return new YangModelInputStreamAdapter(null, name, stringInput );
+ return new YangModelInputStreamAdapter(null, name, new ByteArrayInputStream(module.getBytes(Charsets.UTF_8)));
}
}
leaf connection-timeout-millis {
description "Specifies timeout in milliseconds after which connection must be established.";
type uint32;
- default 5000;
+ default 20000;
}
leaf max-connection-attempts {
<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;
- }
-}
contact "Martin Bobak <mbobak@cisco.com>";
description
- "This module contains the definition of types related to
- Internet Assigned Numbers Authority.
+ "This module contains the definition of methods related to
+ sal remote model.
Copyright (c)2013 Cisco Systems, Inc. All rights reserved.
notification data-changed-notification {
description "Data change notification.";
- leaf data-change-event {
- type instance-identifier;
+ list data-change-event {
+ key path;
+ leaf path {
+ type instance-identifier;
+ }
+ leaf store {
+ type enumeration {
+ enum config;
+ enum operation;
+ }
+ }
+ leaf operation {
+ type enumeration {
+ enum created;
+ enum updated;
+ enum deleted;
+ }
+ }
+ anyxml data{
+ description "DataObject ";
+ }
}
}
Broker broker = getDomBrokerDependency();
-
-
final int port = getPort() != null ? getPort() : ZEROMQ_ROUTER_PORT;
ServerImpl serverImpl = new ServerImpl(port);
RoutingTableProvider provider = new RoutingTableProvider(bundleContext,serverImpl);
-
RemoteRpcProvider facade = new RemoteRpcProvider(serverImpl, clientImpl);
facade.setRoutingTableProvider(provider );
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
/**
* ZeroMq based implementation of RpcRouter. It implements RouteChangeListener of RoutingTable
public ServerImpl(int port) {
this.port = port;
- this.serverAddress = new StringBuilder(findIpAddress()).
- append(":").
- append(port).
- toString();
}
public RoutingTableProvider getRoutingTableProvider() {
"Remote RPC Server is already running");
status = State.STARTING;
+ _logger.debug("Remote RPC Server is starting...");
+
+ String hostIpAddress = findIpAddress();
+
+ //Log and silently die as per discussion in the bug (bug-362)
+ //https://bugs.opendaylight.org/show_bug.cgi?id=362
+ //
+ // A tracking enhancement defect (bug-366) is created to properly fix this issue
+ //https://bugs.opendaylight.org/show_bug.cgi?id=366
+ //checkState(hostIpAddress != null, "Remote RPC Server could not acquire host ip address");
+
+ if (hostIpAddress == null) {
+ _logger.error("Remote RPC Server could not acquire host ip address. Stopping...");
+ stop();
+ return;
+ }
+
+ this.serverAddress = new StringBuilder(hostIpAddress).
+ append(":").
+ append(port).
+ toString();
+
context = ZMQ.context(1);
remoteServices = new HashSet<QName>();//
serverPool = Executors.newSingleThreadExecutor();//main server thread
* @return
*/
private String findIpAddress() {
- String hostAddress = null;
Enumeration e = null;
try {
e = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e1) {
- e1.printStackTrace();
+ _logger.error("Failed to get list of interfaces", e1);
+ //throw new RuntimeException("Failed to acquire list of interfaces", e1);
+ return null;
}
while (e.hasMoreElements()) {
Enumeration ee = n.getInetAddresses();
while (ee.hasMoreElements()) {
InetAddress i = (InetAddress) ee.nextElement();
- if ((i instanceof Inet4Address) && (i.isSiteLocalAddress()))
- hostAddress = i.getHostAddress();
+ _logger.debug("Trying address {}", i);
+ if ((i instanceof Inet4Address) && (i.isSiteLocalAddress())) {
+ String hostAddress = i.getHostAddress();
+ _logger.debug("Settled on host address {}", hostAddress);
+ return hostAddress;
+ }
}
}
- return hostAddress;
+ _logger.error("Failed to find a suitable host address");
+ return null;
}
/**
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-codec-http</artifactId>
+ <version>4.0.10.Final</version>
+ </dependency>
<!-- Testing Dependencies -->
<dependency>
<version>1.0.9</version>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-parser-impl</artifactId>
- <scope>test</scope>
- </dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
import org.opendaylight.controller.sal.restconf.impl.StructuredData;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@GET
@Path("/modules")
- @Produces({Draft02.MediaTypes.API+JSON,Draft02.MediaTypes.API+XML})
+ @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
+ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public StructuredData getModules();
+ @GET
+ @Path("/modules/{identifier:.+}")
+ @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
+ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+ public StructuredData getModules(@PathParam("identifier") String identifier);
+
+ @GET
+ @Path("/modules/module/{identifier:.+}")
+ @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
+ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+ public StructuredData getModule(@PathParam("identifier") String identifier);
+
+ @GET
+ @Path("/operations")
+ @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
+ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+ public StructuredData getOperations();
+
+ @GET
+ @Path("/operations/{identifier:.+}")
+ @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
+ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+ public StructuredData getOperations(@PathParam("identifier") String identifier);
+
@POST
- @Path("/operations/{identifier}")
+ @Path("/operations/{identifier:.+}")
@Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload);
@POST
- @Path("/operations/{identifier}")
+ @Path("/operations/{identifier:.+}")
@Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
@Path("/config/{identifier:.+}")
public Response deleteConfigurationData(@PathParam("identifier") String identifier);
+ @GET
+ @Path("/streams/stream/{identifier:.+}")
+ public Response subscribeToStream(@PathParam("identifier") String identifier, @Context UriInfo uriInfo);
+
}
+ baseType.getClass().getSimpleName() + ".");
}
- // TODO check InstanceIdentifierTypeDefinition
if (baseType instanceof IdentityrefTypeDefinition) {
if (node.getValue() instanceof QName) {
IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(baseType, mountPoint).serialize(
import org.opendaylight.controller.sal.core.api.mount.MountService;
import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.streams.websockets.WebSocketServer;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
import org.osgi.framework.BundleActivator;
private ServiceTracker<Broker, Broker> brokerServiceTrancker;
private BundleContext bundleContext;
private ProviderSession session;
+ private Thread webSocketServerThread;
@Override
public void onSessionInitiated(ProviderSession session) {
bundleContext = context;
brokerServiceTrancker = new ServiceTracker<>(context, Broker.class, this);
brokerServiceTrancker.open();
+ webSocketServerThread = new Thread(new WebSocketServer());
+ webSocketServerThread.setName("Web socket server");
+ webSocketServerThread.start();
}
@Override
e.printStackTrace();
}
}
+ webSocketServerThread.interrupt();
session.close();
brokerServiceTrancker.close();
}
import com.google.gson.stream.JsonWriter;
@Provider
-@Produces({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON,
- MediaType.APPLICATION_JSON })
+@Produces({ Draft02.MediaTypes.API + RestconfService.JSON, Draft02.MediaTypes.DATA + RestconfService.JSON,
+ Draft02.MediaTypes.OPERATION + RestconfService.JSON, MediaType.APPLICATION_JSON })
public enum StructuredDataToJsonProvider implements MessageBodyWriter<StructuredData> {
INSTANCE;
import org.w3c.dom.Document;
@Provider
-@Produces({ Draft02.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.OPERATION + RestconfService.XML,
- MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+@Produces({ Draft02.MediaTypes.API + RestconfService.XML, Draft02.MediaTypes.DATA + RestconfService.XML,
+ Draft02.MediaTypes.OPERATION + RestconfService.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public enum StructuredDataToXmlProvider implements MessageBodyWriter<StructuredData> {
INSTANCE;
import org.opendaylight.controller.md.sal.common.api.data.DataReader
import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession
import org.opendaylight.controller.sal.core.api.data.DataBrokerService
+import org.opendaylight.controller.sal.core.api.mount.MountInstance
import org.opendaylight.controller.sal.rest.impl.RestconfProvider
+import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter
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.slf4j.LoggerFactory
-import org.opendaylight.controller.sal.core.api.mount.MountInstance
class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
return transaction.commit
}
+ def registerToListenDataChanges(ListenerAdapter listener) {
+ checkPreconditions
+ if (listener.listening) {
+ return;
+ }
+ val registration = dataService.registerDataChangeListener(listener.path, listener)
+ listener.setRegistration(registration)
+ }
+
}
package org.opendaylight.controller.sal.restconf.impl
import com.google.common.base.Preconditions
+import com.google.common.base.Splitter
import com.google.common.collect.BiMap
import com.google.common.collect.FluentIterable
import com.google.common.collect.HashBiMap
+import com.google.common.collect.Lists
import java.net.URI
import java.net.URLDecoder
import java.net.URLEncoder
onGlobalContextUpdated(schemas)
}
- public def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) {
+ def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) {
+ return restconfInstance.toIdentifier(false)
+ }
+
+ def InstanceIdWithSchemaNode toMountPointIdentifier(String restconfInstance) {
+ return restconfInstance.toIdentifier(true)
+ }
+
+ private def InstanceIdWithSchemaNode toIdentifier(String restconfInstance, boolean toMountPointIdentifier) {
checkPreconditions
- val pathArgs = restconfInstance.split("/");
+ val pathArgs = Lists.newArrayList(Splitter.on("/").split(restconfInstance))
+ pathArgs.omitFirstAndLastEmptyString
if (pathArgs.empty) {
return null;
}
- if (pathArgs.head.empty) {
- pathArgs.remove(0)
- }
val startModule = pathArgs.head.toModuleName();
if (startModule === null) {
throw new ResponseException(BAD_REQUEST, "First node in URI has to be in format \"moduleName:nodeName\"")
}
- val iiWithSchemaNode = collectPathArguments(InstanceIdentifier.builder(), pathArgs,
- globalSchema.getLatestModule(startModule), null);
+ var InstanceIdWithSchemaNode iiWithSchemaNode = null;
+ if (toMountPointIdentifier) {
+ iiWithSchemaNode = collectPathArguments(InstanceIdentifier.builder(), pathArgs,
+ globalSchema.getLatestModule(startModule), null, true);
+ } else {
+ iiWithSchemaNode = collectPathArguments(InstanceIdentifier.builder(), pathArgs,
+ globalSchema.getLatestModule(startModule), null, false);
+ }
if (iiWithSchemaNode === null) {
throw new ResponseException(BAD_REQUEST, "URI has bad format")
}
return iiWithSchemaNode
}
+ private def omitFirstAndLastEmptyString(List<String> list) {
+ if (list.empty) {
+ return list;
+ }
+ if (list.head.empty) {
+ list.remove(0)
+ }
+ if (list.empty) {
+ return list;
+ }
+ if (list.last.empty) {
+ list.remove(list.indexOf(list.last))
+ }
+ return list;
+ }
+
private def getLatestModule(SchemaContext schema, String moduleName) {
checkArgument(schema !== null);
checkArgument(moduleName !== null && !moduleName.empty)
return moduleSchemas?.filterLatestModule
}
+ def findModuleByNameAndRevision(QName module) {
+ checkPreconditions
+ checkArgument(module !== null && module.localName !== null && module.revision !== null)
+ return globalSchema.findModuleByName(module.localName, module.revision)
+ }
+
+ def findModuleByNameAndRevision(MountInstance mountPoint, QName module) {
+ checkPreconditions
+ checkArgument(module !== null && module.localName !== null && module.revision !== null && mountPoint !== null)
+ return mountPoint.schemaContext?.findModuleByName(module.localName, module.revision)
+ }
+
+ def getDataNodeContainerFor(InstanceIdentifier path) {
+ checkPreconditions
+ val elements = path.path;
+ val startQName = elements.head.nodeType;
+ val initialModule = globalSchema.findModuleByNamespaceAndRevision(startQName.namespace, startQName.revision)
+ var node = initialModule as DataNodeContainer;
+ for (element : elements) {
+ val potentialNode = node.childByQName(element.nodeType);
+ if (potentialNode === null || !potentialNode.listOrContainer) {
+ return null
+ }
+ node = potentialNode as DataNodeContainer
+ }
+ return node
+ }
+
def String toFullRestconfIdentifier(InstanceIdentifier path) {
checkPreconditions
val elements = path.path;
val ret = new StringBuilder();
- val startQName = elements.get(0).nodeType;
+ val startQName = elements.head.nodeType;
val initialModule = globalSchema.findModuleByNamespaceAndRevision(startQName.namespace, startQName.revision)
- var node = initialModule as DataSchemaNode;
+ var node = initialModule as DataNodeContainer;
for (element : elements) {
- node = node.childByQName(element.nodeType);
- ret.append(element.toRestconfIdentifier(node));
+ val potentialNode = node.childByQName(element.nodeType);
+ if (!potentialNode.listOrContainer) {
+ return null
+ }
+ node = potentialNode as DataNodeContainer
+ ret.append(element.convertToRestconfIdentifier(node));
}
return ret.toString
}
- private def dispatch CharSequence toRestconfIdentifier(NodeIdentifier argument, DataSchemaNode node) {
+ private def dispatch CharSequence convertToRestconfIdentifier(NodeIdentifier argument, ContainerSchemaNode node) {
'''/«argument.nodeType.toRestconfIdentifier()»'''
}
- private def dispatch CharSequence toRestconfIdentifier(NodeIdentifierWithPredicates argument, ListSchemaNode node) {
+ private def dispatch CharSequence convertToRestconfIdentifier(NodeIdentifierWithPredicates argument, ListSchemaNode node) {
val nodeIdentifier = argument.nodeType.toRestconfIdentifier();
val keyValues = argument.keyValues;
return '''/«nodeIdentifier»/«FOR key : node.keyDefinition SEPARATOR "/"»«keyValues.get(key).toUriString»«ENDFOR»'''
}
- private def dispatch CharSequence toRestconfIdentifier(PathArgument argument, DataSchemaNode node) {
+ private def dispatch CharSequence convertToRestconfIdentifier(PathArgument argument, DataNodeContainer node) {
throw new IllegalArgumentException("Conversion of generic path argument is not supported");
}
return module?.namespace
}
+ def getAllModules(MountInstance mountPoint) {
+ checkPreconditions
+ return mountPoint?.schemaContext?.modules
+ }
+
+ def getAllModules() {
+ checkPreconditions
+ return globalSchema.modules
+ }
+
def CharSequence toRestconfIdentifier(QName qname) {
checkPreconditions
var module = uriToModuleName.get(qname.namespace)
return container.dataNodeChildByQName(name);
}
+ private static dispatch def DataSchemaNode childByQName(Module container, QName name) {
+ return container.dataNodeChildByQName(name);
+ }
+
private static dispatch def DataSchemaNode childByQName(DataSchemaNode container, QName name) {
return null;
}
}
private def InstanceIdWithSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List<String> strings,
- DataNodeContainer parentNode, MountInstance mountPoint) {
+ DataNodeContainer parentNode, MountInstance mountPoint, boolean returnJustMountPoint) {
checkNotNull(strings)
if (parentNode === null) {
return null;
throw new ResponseException(BAD_REQUEST, "Mount point does not contain any schema with modules.")
}
+ if (returnJustMountPoint) {
+ return new InstanceIdWithSchemaNode(InstanceIdentifier.builder().toInstance, mountPointSchema, mount)
+ }
+
if (strings.size == 1) { // any data node is not behind mount point
return new InstanceIdWithSchemaNode(InstanceIdentifier.builder().toInstance, mountPointSchema, mount)
}
}
return collectPathArguments(InstanceIdentifier.builder(), strings.subList(1, strings.size),
- moduleBehindMountPoint, mount);
+ moduleBehindMountPoint, mount, returnJustMountPoint);
}
var Module module = null;
}
}
- if (!(targetNode instanceof ListSchemaNode) && !(targetNode instanceof ContainerSchemaNode)) {
+ if (!targetNode.isListOrContainer) {
throw new ResponseException(BAD_REQUEST,"URI has bad format. Node \"" + strings.head + "\" must be Container or List yang type.")
}
// Number of consumed elements
}
if (targetNode instanceof DataNodeContainer) {
val remaining = strings.subList(consumed, strings.length);
- val result = builder.collectPathArguments(remaining, targetNode as DataNodeContainer, mountPoint);
+ val result = builder.collectPathArguments(remaining, targetNode as DataNodeContainer, mountPoint, returnJustMountPoint);
return result
}
private def QName toQName(String name) {
val module = name.toModuleName;
val node = name.toNodeName;
- val namespace = FluentIterable.from(globalSchema.modules.sort[o1,o2 | o1.revision.compareTo(o2.revision)]) //
+ val namespace = FluentIterable.from(globalSchema.modules.sort[o1,o2 | o1.revision.compareTo(o2.revision)])
.transform[QName.create(namespace,revision,it.name)].findFirst[module == localName]
- ;
- return QName.create(namespace,node);
+ if (namespace === null) {
+ return null
+ }
+ return QName.create(namespace, node);
+ }
+
+ private def boolean isListOrContainer(DataSchemaNode node) {
+ return ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode))
}
def getRpcDefinition(String name) {
- return qnameToRpc.get(name.toQName)
+ val validName = name.toQName
+ if (validName === null) {
+ return null
+ }
+ return qnameToRpc.get(validName)
}
override onGlobalContextUpdated(SchemaContext context) {
package org.opendaylight.controller.sal.restconf.impl
import com.google.common.base.Preconditions
+import com.google.common.base.Splitter
+import com.google.common.collect.Lists
import java.net.URI
+import java.text.ParseException
+import java.text.SimpleDateFormat
import java.util.ArrayList
import java.util.HashMap
import java.util.List
+import java.util.Set
import javax.ws.rs.core.Response
+import javax.ws.rs.core.UriInfo
import org.opendaylight.controller.md.sal.common.api.TransactionStatus
import org.opendaylight.controller.sal.core.api.mount.MountInstance
import org.opendaylight.controller.sal.rest.api.RestconfService
+import org.opendaylight.controller.sal.streams.listeners.Notificator
+import org.opendaylight.controller.sal.streams.websockets.WebSocketServer
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.model.api.SchemaContext
import org.opendaylight.yangtools.yang.model.api.TypeDefinition
import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
+import org.opendaylight.yangtools.yang.model.util.EmptyType
+import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder
+import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder
import static javax.ws.rs.core.Response.Status.*
val static RestconfImpl INSTANCE = new RestconfImpl
val static MOUNT_POINT_MODULE_NAME = "ietf-netconf"
+ val static REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd")
+ val static RESTCONF_MODULE_DRAFT02_REVISION = "2013-10-19"
+ val static RESTCONF_MODULE_DRAFT02_NAME = "ietf-restconf"
+ val static RESTCONF_MODULE_DRAFT02_NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-restconf"
+ val static RESTCONF_MODULE_DRAFT02_RESTCONF_GROUPING_SCHEMA_NODE = "restconf"
+ val static RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE = "restconf"
+ val static RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE = "modules"
+ val static RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE = "module"
+ val static RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE = "operations"
+ val static SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"
+ val static SAL_REMOTE_RPC_SUBSRCIBE = "create-data-change-event-subscription"
@Property
BrokerFacade broker
}
override getModules() {
- throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ val restconfModule = getRestconfModule()
+ val List<Node<?>> modulesAsData = new ArrayList
+ val moduleSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE)
+ for (module : allModules) {
+ modulesAsData.add(module.toModuleCompositeNode(moduleSchemaNode))
+ }
+ val modulesSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE)
+ val modulesNode = NodeFactory.createImmutableCompositeNode(modulesSchemaNode.QName, null, modulesAsData)
+ return new StructuredData(modulesNode, modulesSchemaNode, null)
+ }
+
+ override getModules(String identifier) {
+ var Set<Module> modules = null
+ var MountInstance mountPoint = null
+ if (identifier.contains(ControllerContext.MOUNT)) {
+ mountPoint = identifier.toMountPointIdentifier.mountPoint
+ modules = mountPoint.allModules
+ } else {
+ throw new ResponseException(BAD_REQUEST, "URI has bad format. If modules behind mount point should be showed, URI has to end with " + ControllerContext.MOUNT)
+ }
+ val List<Node<?>> modulesAsData = new ArrayList
+ val moduleSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE)
+ for (module : modules) {
+ modulesAsData.add(module.toModuleCompositeNode(moduleSchemaNode))
+ }
+ val modulesSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE)
+ val modulesNode = NodeFactory.createImmutableCompositeNode(modulesSchemaNode.QName, null, modulesAsData)
+ return new StructuredData(modulesNode, modulesSchemaNode, mountPoint)
+ }
+
+ override getModule(String identifier) {
+ val moduleNameAndRevision = identifier.moduleNameAndRevision
+ var Module module = null
+ var MountInstance mountPoint = null
+ if (identifier.contains(ControllerContext.MOUNT)) {
+ mountPoint = identifier.toMountPointIdentifier.mountPoint
+ module = mountPoint.findModuleByNameAndRevision(moduleNameAndRevision)
+ } else {
+ module = findModuleByNameAndRevision(moduleNameAndRevision)
+ }
+ if (module === null) {
+ throw new ResponseException(BAD_REQUEST,
+ "Module with name '" + moduleNameAndRevision.localName + "' and revision '" +
+ moduleNameAndRevision.revision + "' was not found.")
+ }
+ val moduleSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE)
+ val moduleNode = module.toModuleCompositeNode(moduleSchemaNode)
+ return new StructuredData(moduleNode, moduleSchemaNode, mountPoint)
+ }
+
+ override getOperations() {
+ return operationsFromModulesToStructuredData(allModules,null)
+ }
+
+ override getOperations(String identifier) {
+ var Set<Module> modules = null
+ var MountInstance mountPoint = null
+ if (identifier.contains(ControllerContext.MOUNT)) {
+ mountPoint = identifier.toMountPointIdentifier.mountPoint
+ modules = mountPoint.allModules
+ } else {
+ throw new ResponseException(BAD_REQUEST, "URI has bad format. If operations behind mount point should be showed, URI has to end with " + ControllerContext.MOUNT)
+ }
+ return operationsFromModulesToStructuredData(modules,mountPoint)
+ }
+
+ private def StructuredData operationsFromModulesToStructuredData(Set<Module> modules,MountInstance mountPoint) {
+ val List<Node<?>> operationsAsData = new ArrayList
+ val operationsSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE)
+ val fakeOperationsSchemaNode = new ContainerSchemaNodeBuilder(RESTCONF_MODULE_DRAFT02_NAME, 0, operationsSchemaNode.QName, operationsSchemaNode.path)
+ for (module : modules) {
+ for (rpc : module.rpcs) {
+ operationsAsData.add(NodeFactory.createImmutableSimpleNode(rpc.QName, null, null))
+ val fakeRpcSchemaNode = new LeafSchemaNodeBuilder(module.name, 0, rpc.QName, null)
+ fakeRpcSchemaNode.setAugmenting(true)
+ fakeRpcSchemaNode.setType(EmptyType.instance)
+ fakeOperationsSchemaNode.addChildNode(fakeRpcSchemaNode.build)
+ }
+ }
+ val operationsNode = NodeFactory.createImmutableCompositeNode(operationsSchemaNode.QName, null, operationsAsData)
+ return new StructuredData(operationsNode, fakeOperationsSchemaNode.build, mountPoint)
+ }
+
+ private def Module getRestconfModule() {
+ val restconfModule = findModuleByNameAndRevision(
+ QName.create(RESTCONF_MODULE_DRAFT02_NAMESPACE, RESTCONF_MODULE_DRAFT02_REVISION,
+ RESTCONF_MODULE_DRAFT02_NAME))
+ if (restconfModule === null) {
+ throw new ResponseException(INTERNAL_SERVER_ERROR, "Restconf module was not found.")
+ }
+ return restconfModule
+ }
+
+ private def QName getModuleNameAndRevision(String identifier) {
+ val indexOfMountPointFirstLetter = identifier.indexOf(ControllerContext.MOUNT)
+ var moduleNameAndRevision = "";
+ if (indexOfMountPointFirstLetter !== -1) { // module and revision is behind mount point string
+ moduleNameAndRevision = identifier.substring(indexOfMountPointFirstLetter + ControllerContext.MOUNT.length)
+ } else (
+ moduleNameAndRevision = identifier
+ )
+ val pathArgs = Lists.newArrayList(Splitter.on("/").omitEmptyStrings.split(moduleNameAndRevision))
+ if (pathArgs.length < 2) {
+ throw new ResponseException(BAD_REQUEST,
+ "URI has bad format. End of URI should be in format 'moduleName/yyyy-MM-dd'")
+ }
+ try {
+ val moduleName = pathArgs.head
+ val moduleRevision = REVISION_FORMAT.parse(pathArgs.get(1))
+ return QName.create(null, moduleRevision, moduleName)
+ } catch(ParseException e) {
+ throw new ResponseException(BAD_REQUEST, "URI has bad format. It should be 'moduleName/yyyy-MM-dd'")
+ }
+ }
+
+ private def CompositeNode toModuleCompositeNode(Module module, DataSchemaNode moduleSchemaNode) {
+ val List<Node<?>> moduleNodeValues = new ArrayList
+ val nameSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("name").head
+ moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(nameSchemaNode.QName, null, module.name))
+ val revisionSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("revision").head
+ moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(revisionSchemaNode.QName, null, REVISION_FORMAT.format(module.revision)))
+ val namespaceSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("namespace").head
+ moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(namespaceSchemaNode.QName, null, module.namespace.toString))
+ val featureSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("feature").head
+ for (feature : module.features) {
+ moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(featureSchemaNode.QName, null, feature.QName.localName))
+ }
+ return NodeFactory.createImmutableCompositeNode(moduleSchemaNode.QName, null, moduleNodeValues)
+ }
+
+ private def DataSchemaNode getSchemaNode(Module restconfModule, String schemaNodeName) {
+ val restconfGrouping = restconfModule.groupings.filter[g|g.QName.localName == RESTCONF_MODULE_DRAFT02_RESTCONF_GROUPING_SCHEMA_NODE].head
+ val restconfContainer = restconfGrouping.findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE).head
+ if (schemaNodeName == RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE) {
+ return (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE).head
+ } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE) {
+ return (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE).head
+ } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE) {
+ val modules = (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE).head
+ return (modules as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE).head
+ }
+ return null
}
override getRoot() {
}
override invokeRpc(String identifier, CompositeNode payload) {
+ val rpc = identifier.rpcDefinition
+ if (rpc === null) {
+ throw new ResponseException(NOT_FOUND, "RPC does not exist.");
+ }
+ if (rpc.QName.namespace.toString == SAL_REMOTE_NAMESPACE && rpc.QName.localName == SAL_REMOTE_RPC_SUBSRCIBE) {
+ val value = normalizeNode(payload, rpc.input, null)
+ val pathNode = value?.getFirstSimpleByName(QName.create(rpc.QName, "path"))
+ val pathValue = pathNode?.value
+ if (pathValue === null && !(pathValue instanceof InstanceIdentifier)) {
+ throw new ResponseException(INTERNAL_SERVER_ERROR, "Instance identifier was not normalized correctly.");
+ }
+ val pathIdentifier = (pathValue as InstanceIdentifier)
+ var String streamName = null
+ if (!pathIdentifier.path.nullOrEmpty) {
+ streamName = Notificator.createStreamNameFromUri(pathIdentifier.toFullRestconfIdentifier)
+ }
+ if (streamName.nullOrEmpty) {
+ throw new ResponseException(BAD_REQUEST, "Path is empty or contains data node which is not Container or List build-in type.");
+ }
+ val streamNameNode = NodeFactory.createImmutableSimpleNode(QName.create(rpc.output.QName, "stream-name"), null, streamName)
+ val List<Node<?>> output = new ArrayList
+ output.add(streamNameNode)
+ val responseData = NodeFactory.createMutableCompositeNode(rpc.output.QName, null, output, null, null)
+
+ if (!Notificator.existListenerFor(pathIdentifier)) {
+ Notificator.createListener(pathIdentifier, streamName)
+ }
+
+ return new StructuredData(responseData, rpc.output, null)
+ }
return callRpc(identifier.rpcDefinition, payload)
}
}
}
+ override subscribeToStream(String identifier, UriInfo uriInfo) {
+ val streamName = Notificator.createStreamNameFromUri(identifier)
+ if (streamName.nullOrEmpty) {
+ throw new ResponseException(BAD_REQUEST, "Stream name is empty.")
+ }
+ val listener = Notificator.getListenerFor(streamName);
+ if (listener === null) {
+ throw new ResponseException(BAD_REQUEST, "Stream was not found.")
+ }
+ broker.registerToListenDataChanges(listener)
+ val uriBuilder = uriInfo.getAbsolutePathBuilder()
+ val uriToWebsocketServer = uriBuilder.port(WebSocketServer.PORT).replacePath(streamName).build()
+ return Response.status(OK).location(uriToWebsocketServer).build
+ }
+
private def dispatch URI namespace(CompositeNode data) {
return data.nodeType.namespace
}
--- /dev/null
+package org.opendaylight.controller.sal.streams.listeners;
+
+import io.netty.channel.Channel;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.util.internal.ConcurrentSet;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.Executors;
+
+import javax.activation.UnsupportedDataTypeException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.rest.impl.XmlMapper;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+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.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.google.common.base.Preconditions;
+import com.google.common.eventbus.AsyncEventBus;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+
+public class ListenerAdapter implements DataChangeListener {
+
+ private static final Logger logger = LoggerFactory.getLogger(ListenerAdapter.class);
+ private final XmlMapper xmlMapper = new XmlMapper();
+ private final SimpleDateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssZ");
+
+ private final InstanceIdentifier path;
+ private ListenerRegistration<DataChangeListener> registration;
+ private final String streamName;
+ private Set<Channel> subscribers = new ConcurrentSet<>();
+ private final EventBus eventBus;
+ private final EventBusChangeRecorder eventBusChangeRecorder;
+
+ ListenerAdapter(InstanceIdentifier path, String streamName) {
+ Preconditions.checkNotNull(path);
+ Preconditions.checkArgument(streamName != null && !streamName.isEmpty());
+ this.path = path;
+ this.streamName = streamName;
+ eventBus = new AsyncEventBus(Executors.newSingleThreadExecutor());
+ eventBusChangeRecorder = new EventBusChangeRecorder();
+ eventBus.register(eventBusChangeRecorder);
+ }
+
+ @Override
+ public void onDataChanged(DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
+ if (!change.getCreatedConfigurationData().isEmpty() || !change.getCreatedOperationalData().isEmpty()
+ || !change.getUpdatedConfigurationData().isEmpty() || !change.getUpdatedOperationalData().isEmpty()
+ || !change.getRemovedConfigurationData().isEmpty() || !change.getRemovedOperationalData().isEmpty()) {
+ String xml = prepareXmlFrom(change);
+ Event event = new Event(EventType.NOTIFY);
+ event.setData(xml);
+ eventBus.post(event);
+ }
+ }
+
+ private final class EventBusChangeRecorder {
+ @Subscribe public void recordCustomerChange(Event event) {
+ if (event.getType() == EventType.REGISTER) {
+ Channel subscriber = event.getSubscriber();
+ if (!subscribers.contains(subscriber)) {
+ subscribers.add(subscriber);
+ }
+ } else if (event.getType() == EventType.DEREGISTER) {
+ subscribers.remove(event.getSubscriber());
+ Notificator.removeListenerIfNoSubscriberExists(ListenerAdapter.this);
+ } else if (event.getType() == EventType.NOTIFY) {
+ for (Channel subscriber : subscribers) {
+ if (subscriber.isActive()) {
+ logger.debug("Data are sent to subscriber {}:", subscriber.remoteAddress());
+ subscriber.writeAndFlush(new TextWebSocketFrame(event.getData()));
+ } else {
+ logger.debug("Subscriber {} is removed - channel is not active yet.", subscriber.remoteAddress());
+ subscribers.remove(subscriber);
+ }
+ }
+ }
+ }
+ }
+
+ private final class Event {
+ private final EventType type;
+ private Channel subscriber;
+ private String data;
+
+ public Event(EventType type) {
+ this.type = type;
+ }
+
+ public Channel getSubscriber() {
+ return subscriber;
+ }
+
+ public void setSubscriber(Channel subscriber) {
+ this.subscriber = subscriber;
+ }
+
+ public String getData() {
+ return data;
+ }
+
+ public void setData(String data) {
+ this.data = data;
+ }
+
+ public EventType getType() {
+ return type;
+ }
+ }
+
+ private enum EventType {
+ REGISTER,
+ DEREGISTER,
+ NOTIFY;
+ }
+
+ private String prepareXmlFrom(DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
+ Document doc = createDocument();
+ Element notificationElement = doc.createElementNS("urn:ietf:params:xml:ns:netconf:notification:1.0",
+ "notification");
+ doc.appendChild(notificationElement);
+
+ Element eventTimeElement = doc.createElement("eventTime");
+ eventTimeElement.setTextContent(toRFC3339(new Date()));
+ notificationElement.appendChild(eventTimeElement);
+
+ Element dataChangedNotificationEventElement = doc.createElementNS(
+ "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "data-changed-notification");
+ addValuesToDataChangedNotificationEventElement(doc, dataChangedNotificationEventElement, change);
+ notificationElement.appendChild(dataChangedNotificationEventElement);
+
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+ transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+ transformer.transform(new DOMSource(doc), new StreamResult(new OutputStreamWriter(out, "UTF-8")));
+ byte[] charData = out.toByteArray();
+ return new String(charData, "UTF-8");
+ } catch (TransformerException | UnsupportedEncodingException e) {
+ String msg = "Error during transformation of Document into String";
+ logger.error(msg, e);
+ return msg;
+ }
+ }
+
+ private String toRFC3339(Date d) {
+ return rfc3339.format(d).replaceAll("(\\d\\d)(\\d\\d)$", "$1:$2");
+ }
+
+ private Document createDocument() {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ Document doc = null;
+ try {
+ DocumentBuilder bob = dbf.newDocumentBuilder();
+ doc = bob.newDocument();
+ } catch (ParserConfigurationException e) {
+ return null;
+ }
+ return doc;
+ }
+
+ private void addValuesToDataChangedNotificationEventElement(Document doc,
+ Element dataChangedNotificationEventElement, DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
+ addValuesFromDataToElement(doc, change.getCreatedConfigurationData(), dataChangedNotificationEventElement, Store.CONFIG, Operation.CREATED);
+ addValuesFromDataToElement(doc, change.getCreatedOperationalData(), dataChangedNotificationEventElement, Store.OPERATION, Operation.CREATED);
+ if (change.getCreatedConfigurationData().isEmpty()) {
+ addValuesFromDataToElement(doc, change.getUpdatedConfigurationData(), dataChangedNotificationEventElement, Store.CONFIG, Operation.UPDATED);
+ }
+ if (change.getCreatedOperationalData().isEmpty()) {
+ addValuesFromDataToElement(doc, change.getUpdatedOperationalData(), dataChangedNotificationEventElement, Store.OPERATION, Operation.UPDATED);
+ }
+ addValuesFromDataToElement(doc, change.getRemovedConfigurationData(), dataChangedNotificationEventElement, Store.CONFIG, Operation.DELETED);
+ addValuesFromDataToElement(doc, change.getRemovedOperationalData(), dataChangedNotificationEventElement, Store.OPERATION, Operation.DELETED);
+ }
+
+ private void addValuesFromDataToElement(Document doc, Set<InstanceIdentifier> data, Element element, Store store,
+ Operation operation) {
+ if (data == null || data.isEmpty()) {
+ return;
+ }
+ for (InstanceIdentifier path : data) {
+ Node node = createDataChangeEventElement(doc, path, null, store, operation);
+ element.appendChild(node);
+ }
+ }
+
+ private void addValuesFromDataToElement(Document doc, Map<InstanceIdentifier, CompositeNode> data, Element element, Store store,
+ Operation operation) {
+ if (data == null || data.isEmpty()) {
+ return;
+ }
+ for (Entry<InstanceIdentifier, CompositeNode> entry : data.entrySet()) {
+ Node node = createDataChangeEventElement(doc, entry.getKey(), entry.getValue(), store, operation);
+ element.appendChild(node);
+ }
+ }
+
+ private Node createDataChangeEventElement(Document doc, InstanceIdentifier path, CompositeNode data, Store store,
+ Operation operation) {
+ Element dataChangeEventElement = doc.createElement("data-change-event");
+
+ Element pathElement = doc.createElement("path");
+ addPathAsValueToElement(path, pathElement);
+ dataChangeEventElement.appendChild(pathElement);
+
+ Element storeElement = doc.createElement("store");
+ storeElement.setTextContent(store.value);
+ dataChangeEventElement.appendChild(storeElement);
+
+ Element operationElement = doc.createElement("operation");
+ operationElement.setTextContent(operation.value);
+ dataChangeEventElement.appendChild(operationElement);
+
+ if (data != null) {
+ Element dataElement = doc.createElement("data");
+ Node dataAnyXml = translateToXml(path, data);
+ Node adoptedNode = doc.adoptNode(dataAnyXml);
+ dataElement.appendChild(adoptedNode);
+ dataChangeEventElement.appendChild(dataElement);
+ }
+
+ return dataChangeEventElement;
+ }
+
+ private Node translateToXml(InstanceIdentifier path, CompositeNode data) {
+ DataNodeContainer schemaNode = ControllerContext.getInstance().getDataNodeContainerFor(path);
+ if (schemaNode == null) {
+ logger.info("Path '{}' contains node with unsupported type (supported type is Container or List) or some node was not found.", path);
+ return null;
+ }
+ try {
+ Document xml = xmlMapper.write(data, schemaNode);
+ return xml.getFirstChild();
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("Error occured during translation of notification to XML.", e);
+ return null;
+ }
+ }
+
+ private void addPathAsValueToElement(InstanceIdentifier path, Element element) {
+ // Map< key = namespace, value = prefix>
+ Map<String, String> prefixes = new HashMap<>();
+ InstanceIdentifier instanceIdentifier = path;
+ StringBuilder textContent = new StringBuilder();
+ for (PathArgument pathArgument : instanceIdentifier.getPath()) {
+ textContent.append("/");
+ writeIdentifierWithNamespacePrefix(element, textContent, pathArgument.getNodeType(), prefixes);
+ if (pathArgument instanceof NodeIdentifierWithPredicates) {
+ Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues();
+ for (QName keyValue : predicates.keySet()) {
+ String predicateValue = String.valueOf(predicates.get(keyValue));
+ textContent.append("[");
+ writeIdentifierWithNamespacePrefix(element, textContent, keyValue, prefixes);
+ textContent.append("='");
+ textContent.append(predicateValue);
+ textContent.append("'");
+ textContent.append("]");
+ }
+ } else if (pathArgument instanceof NodeWithValue) {
+ textContent.append("[.='");
+ textContent.append(((NodeWithValue)pathArgument).getValue());
+ textContent.append("'");
+ textContent.append("]");
+ }
+ }
+ element.setTextContent(textContent.toString());
+ }
+
+ private static void writeIdentifierWithNamespacePrefix(Element element, StringBuilder textContent, QName qName,
+ Map<String, String> prefixes) {
+ String namespace = qName.getNamespace().toString();
+ String prefix = prefixes.get(namespace);
+ if (prefix == null) {
+ prefix = qName.getPrefix();
+ if (prefix == null || prefix.isEmpty() || prefixes.containsValue(prefix)) {
+ prefix = generateNewPrefix(prefixes.values());
+ }
+ }
+
+ element.setAttribute("xmlns:" + prefix, namespace.toString());
+ textContent.append(prefix);
+ prefixes.put(namespace, prefix);
+
+ textContent.append(":");
+ textContent.append(qName.getLocalName());
+ }
+
+ private static String generateNewPrefix(Collection<String> prefixes) {
+ StringBuilder result = null;
+ Random random = new Random();
+ do {
+ result = new StringBuilder();
+ for (int i = 0; i < 4; i++) {
+ int randomNumber = 0x61 + (Math.abs(random.nextInt()) % 26);
+ result.append(Character.toChars(randomNumber));
+ }
+ } while (prefixes.contains(result.toString()));
+
+ return result.toString();
+ }
+
+ public InstanceIdentifier getPath() {
+ return path;
+ }
+
+ public void setRegistration(ListenerRegistration<DataChangeListener> registration) {
+ this.registration = registration;
+ }
+
+ public String getStreamName() {
+ return streamName;
+ }
+
+ public void close() throws Exception {
+ subscribers = new ConcurrentSet<>();
+ registration.close();
+ registration = null;
+ eventBus.unregister(eventBusChangeRecorder);
+ }
+
+ public boolean isListening() {
+ return registration == null ? false : true;
+ }
+
+ public void addSubscriber(Channel subscriber) {
+ if (!subscriber.isActive()) {
+ logger.debug("Channel is not active between websocket server and subscriber {}"
+ + subscriber.remoteAddress());
+ }
+ Event event = new Event(EventType.REGISTER);
+ event.setSubscriber(subscriber);
+ eventBus.post(event);
+ }
+
+ public void removeSubscriber(Channel subscriber) {
+ logger.debug("Subscriber {} is removed.", subscriber.remoteAddress());
+ Event event = new Event(EventType.DEREGISTER);
+ event.setSubscriber(subscriber);
+ eventBus.post(event);
+ }
+
+ public boolean hasSubscribers() {
+ return !subscribers.isEmpty();
+ }
+
+ private static enum Store {
+ CONFIG("config"),
+ OPERATION("operation");
+
+ private final String value;
+
+ private Store(String value) {
+ this.value = value;
+ }
+ }
+
+ private static enum Operation {
+ CREATED("created"),
+ UPDATED("updated"),
+ DELETED("deleted");
+
+ private final String value;
+
+ private Operation(String value) {
+ this.value = value;
+ }
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.streams.listeners;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class Notificator {
+
+ private static Map<String, ListenerAdapter> listenersByStreamName = new ConcurrentHashMap<>();
+ private static Map<InstanceIdentifier, ListenerAdapter> listenersByInstanceIdentifier = new ConcurrentHashMap<>();
+ private static final Lock lock = new ReentrantLock();
+
+ private Notificator() {
+ }
+
+ public static ListenerAdapter getListenerFor(String streamName) {
+ return listenersByStreamName.get(streamName);
+ }
+
+ public static ListenerAdapter getListenerFor(InstanceIdentifier path) {
+ return listenersByInstanceIdentifier.get(path);
+ }
+
+ public static boolean existListenerFor(InstanceIdentifier path) {
+ return listenersByInstanceIdentifier.containsKey(path);
+ }
+
+ public static ListenerAdapter createListener(InstanceIdentifier path, String streamName) {
+ ListenerAdapter listener = new ListenerAdapter(path, streamName);
+ try {
+ lock.lock();
+ listenersByInstanceIdentifier.put(path, listener);
+ listenersByStreamName.put(streamName, listener);
+ } finally {
+ lock.unlock();
+ }
+ return listener;
+ }
+
+ public static void removeListener(InstanceIdentifier path) {
+ ListenerAdapter listener = listenersByInstanceIdentifier.get(path);
+ deleteListener(listener);
+ }
+
+ public static String createStreamNameFromUri(String uri) {
+ if (uri == null) {
+ return null;
+ }
+ String result = uri;
+ if (result.startsWith("/")) {
+ result = result.substring(1);
+ }
+ if (result.endsWith("/")) {
+ result = result.substring(0, result.length());
+ }
+ return result;
+ }
+
+ public static void removeAllListeners() {
+ for (ListenerAdapter listener : listenersByInstanceIdentifier.values()) {
+ try {
+ listener.close();
+ } catch (Exception e) {
+ }
+ }
+ try {
+ lock.lock();
+ listenersByStreamName = new ConcurrentHashMap<>();
+ listenersByInstanceIdentifier = new ConcurrentHashMap<>();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public static void removeListenerIfNoSubscriberExists(ListenerAdapter listener) {
+ if (!listener.hasSubscribers()) {
+ deleteListener(listener);
+ }
+ }
+
+ private static void deleteListener(ListenerAdapter listener) {
+ if (listener != null) {
+ try {
+ listener.close();
+ } catch (Exception e) {
+ }
+ try {
+ lock.lock();
+ listenersByInstanceIdentifier.remove(listener.getPath());
+ listenersByStreamName.remove(listener.getStreamName());
+ } finally {
+ lock.unlock();
+ }
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.sal.streams.websockets;
+
+import org.opendaylight.controller.sal.streams.listeners.Notificator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+
+public class WebSocketServer implements Runnable {
+
+ private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
+
+ public static final int PORT = 8181;
+ private EventLoopGroup bossGroup;
+ private EventLoopGroup workerGroup;
+
+ @Override
+ public void run() {
+ bossGroup = new NioEventLoopGroup();
+ workerGroup = new NioEventLoopGroup();
+ try {
+ ServerBootstrap b = new ServerBootstrap();
+ b.group(bossGroup, workerGroup)
+ .channel(NioServerSocketChannel.class)
+ .childHandler(new WebSocketServerInitializer());
+
+ Channel ch = b.bind(PORT).sync().channel();
+ logger.info("Web socket server started at port {}.", PORT);
+
+ ch.closeFuture().sync();
+ } catch (InterruptedException e) {
+ // NOOP
+ } finally {
+ stop();
+ }
+ }
+
+ private void stop() {
+ Notificator.removeAllListeners();
+ if (bossGroup != null) {
+ bossGroup.shutdownGracefully();
+ }
+ if (workerGroup != null) {
+ workerGroup.shutdownGracefully();
+ }
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.streams.websockets;
+
+import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive;
+import static io.netty.handler.codec.http.HttpHeaders.setContentLength;
+import static io.netty.handler.codec.http.HttpHeaders.Names.HOST;
+import static io.netty.handler.codec.http.HttpMethod.GET;
+import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
+import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
+import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
+import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
+import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
+import io.netty.util.CharsetUtil;
+
+import java.io.IOException;
+
+import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.controller.sal.streams.listeners.Notificator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
+
+ private static final Logger logger = LoggerFactory.getLogger(WebSocketServerHandler.class);
+
+ private WebSocketServerHandshaker handshaker;
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
+ if (msg instanceof FullHttpRequest) {
+ handleHttpRequest(ctx, (FullHttpRequest) msg);
+ } else if (msg instanceof WebSocketFrame) {
+ handleWebSocketFrame(ctx, (WebSocketFrame) msg);
+ }
+ }
+
+ private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req)
+ throws Exception {
+ // Handle a bad request.
+ if (!req.getDecoderResult().isSuccess()) {
+ sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
+ return;
+ }
+
+ // Allow only GET methods.
+ if (req.getMethod() != GET) {
+ sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
+ return;
+ }
+
+ String streamName = Notificator.createStreamNameFromUri(req.getUri());
+ ListenerAdapter listener = Notificator.getListenerFor(streamName);
+ if (listener != null) {
+ listener.addSubscriber(ctx.channel());
+ logger.debug("Subscriber successfully registered.");
+ } else {
+ logger.error("Listener for stream with name '{}' was not found.", streamName);
+ sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, INTERNAL_SERVER_ERROR));
+ }
+
+ // Handshake
+ WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
+ getWebSocketLocation(req), null, false);
+ handshaker = wsFactory.newHandshaker(req);
+ if (handshaker == null) {
+ WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel());
+ } else {
+ handshaker.handshake(ctx.channel(), req);
+ }
+
+ }
+
+ private static void sendHttpResponse(ChannelHandlerContext ctx,
+ HttpRequest req, FullHttpResponse res) {
+ // Generate an error page if response getStatus code is not OK (200).
+ if (res.getStatus().code() != 200) {
+ ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8);
+ res.content().writeBytes(buf);
+ buf.release();
+ setContentLength(res, res.content().readableBytes());
+ }
+
+ // Send the response and close the connection if necessary.
+ ChannelFuture f = ctx.channel().writeAndFlush(res);
+ if (!isKeepAlive(req) || res.getStatus().code() != 200) {
+ f.addListener(ChannelFutureListener.CLOSE);
+ }
+ }
+
+ private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) throws IOException {
+ if (frame instanceof CloseWebSocketFrame) {
+ handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
+ String streamName = Notificator.createStreamNameFromUri(((CloseWebSocketFrame) frame).reasonText());
+ ListenerAdapter listener = Notificator.getListenerFor(streamName);
+ if (listener != null) {
+ listener.removeSubscriber(ctx.channel());
+ logger.debug("Subscriber successfully registered.");
+ }
+ Notificator.removeListenerIfNoSubscriberExists(listener);
+ return;
+ } else if (frame instanceof PingWebSocketFrame) {
+ ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
+ return;
+ }
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
+ throws Exception {
+ if (cause instanceof java.nio.channels.ClosedChannelException == false) {
+ //cause.printStackTrace();
+ }
+ ctx.close();
+ }
+
+ private static String getWebSocketLocation(HttpRequest req) {
+ return "http://" + req.headers().get(HOST) + req.getUri();
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.streams.websockets;
+
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpServerCodec;
+
+public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {
+
+ @Override
+ protected void initChannel(SocketChannel ch) throws Exception {
+ ChannelPipeline pipeline = ch.pipeline();
+ pipeline.addLast("codec-http", new HttpServerCodec());
+ pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
+ pipeline.addLast("handler", new WebSocketServerHandler());
+ }
+
+}
+++ /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.sal.restconf.iml.varioustests;
-
-import org.junit.Ignore;
-import org.junit.Test;
-import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
-import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.w3c.dom.Document;
-
-
-public class VariousTest {
-
- @Ignore
- @Test
- public void test() {
- String[] split = "/something:dfsa/s:sda".split("/");
- System.out.println(split.length);
- for (String str : split) {
- System.out.println(">"+str+"<");
- }
-
- }
-
- @Test
- public void loadXml() {
- TestUtils.readInputToCnSn("/varioustest/xmldata.xml", XmlToCompositeNodeProvider.INSTANCE);
-// TestUtils.normalizeCompositeNode(compositeNode, modules, schemaNodePath)
- }
-
- @Test
- public void buildXml() {
-// Document doc;
-// doc.createElementNS(namespaceURI, qualifiedName)
- }
-
-
-}
import java.io.IOException;
import java.util.Collections;
-import java.util.Set;
import javax.ws.rs.WebApplicationException;
import org.junit.BeforeClass;
-import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
import org.opendaylight.controller.sal.restconf.impl.test.DummyType;
import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
import org.slf4j.Logger;
String jsonOutput = null;
jsonOutput = TestUtils
.writeCompNodeWithSchemaContextToOutput(prepareCompositeNode(),
- (Set<Module>) Collections.EMPTY_SET, prepareDataSchemaNode(),
+ Collections.EMPTY_SET, prepareDataSchemaNode(),
StructuredDataToJsonProvider.INSTANCE);
assertNotNull(jsonOutput);
assertTrue(jsonOutput.contains("\"lf1\": \"\""));
*/
package org.opendaylight.controller.sal.restconf.impl.cnsn.to.xml.test;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.Collections;
-import java.util.Set;
import javax.ws.rs.WebApplicationException;
import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
import org.opendaylight.controller.sal.restconf.impl.test.DummyType;
import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
-import org.opendaylight.yangtools.yang.data.api.*;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
import org.slf4j.Logger;
boolean nullPointerExceptionRaised = false;
try {
TestUtils.writeCompNodeWithSchemaContextToOutput(prepareCompositeNode(),
- (Set<Module>) Collections.EMPTY_SET, prepareDataSchemaNode(), StructuredDataToXmlProvider.INSTANCE);
+ Collections.EMPTY_SET, prepareDataSchemaNode(), StructuredDataToXmlProvider.INSTANCE);
} catch (WebApplicationException | IOException e) {
LOG.error("WebApplicationException or IOException was raised");
} catch (NullPointerException e) {
package org.opendaylight.controller.sal.restconf.impl.test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
private static SchemaContext schemaContextTestModule;
private static CompositeNode answerFromGet;
+ private static SchemaContext schemaContextModules;
+ private static SchemaContext schemaContextBehindMountPoint;
+
@BeforeClass
public static void init() throws FileNotFoundException {
schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
restconfImpl.setBroker(brokerFacade);
restconfImpl.setControllerContext(controllerContext);
answerFromGet = prepareCompositeNodeWithIetfInterfacesInterfacesData();
+
+ schemaContextModules = TestUtils.loadSchemaContext("/modules");
+ schemaContextBehindMountPoint = TestUtils.loadSchemaContext("/modules/modules-behind-mount-point");
}
@Override
protected Application configure() {
/* enable/disable Jersey logs to console */
-// enable(TestProperties.LOG_TRAFFIC);
-// enable(TestProperties.DUMP_ENTITY);
-// enable(TestProperties.RECORD_LOG_LEVEL);
-// set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE,
StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
ControllerContext.getInstance().setMountService(mockMountService);
-
+
String uri = createUri("/config/",
"ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont/cont1");
assertEquals(200, get(uri, MediaType.APPLICATION_XML));
@Test
public void getDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException {
- when(brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class),
+ when(
+ brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class),
any(InstanceIdentifier.class))).thenReturn(prepareCnDataForMountPointTest());
MountInstance mountInstance = mock(MountInstance.class);
when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
ControllerContext.getInstance().setMountService(mockMountService);
- String uri = createUri("/config/",
- "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
+ String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
assertEquals(200, get(uri, MediaType.APPLICATION_XML));
}
+ // /modules
+ @Test
+ public void getModulesTest() throws UnsupportedEncodingException, FileNotFoundException {
+ ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
+
+ String uri = createUri("/modules", "");
+
+ Response response = target(uri).request("application/yang.api+json").get();
+ validateModulesResponseJson(response);
+
+ response = target(uri).request("application/yang.api+xml").get();
+ validateModulesResponseXml(response);
+ }
+
+ // /modules/module
+ @Test
+ public void getModuleTest() throws FileNotFoundException, UnsupportedEncodingException {
+ ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
+
+ String uri = createUri("/modules/module/module2/2014-01-02", "");
+
+ Response response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ String responseBody = response.readEntity(String.class);
+ assertTrue("Module2 in xml wasn't found", prepareXmlRegex("module2", "2014-01-02", "module:2", responseBody)
+ .find());
+ String[] split = responseBody.split("<module");
+ assertEquals("<module element is returned more then once",2,split.length);
+
+ response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ responseBody = response.readEntity(String.class);
+ assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
+ .find());
+ split = responseBody.split("\"module\"");
+ assertEquals("\"module\" element is returned more then once",2,split.length);
+
+ }
+
+ // /operations
+ @Test
+ public void getOperationsTest() throws FileNotFoundException, UnsupportedEncodingException {
+ ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
+
+ String uri = createUri("/operations", "");
+
+ Response response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ String responseBody = response.readEntity(String.class);
+ assertTrue("Xml response for /operations dummy-rpc1-module1 is incorrect",
+ validateOperationsResponseXml(responseBody, "dummy-rpc1-module1", "module:1").find());
+ assertTrue("Xml response for /operations dummy-rpc2-module1 is incorrect",
+ validateOperationsResponseXml(responseBody, "dummy-rpc2-module1", "module:1").find());
+ assertTrue("Xml response for /operations dummy-rpc1-module2 is incorrect",
+ validateOperationsResponseXml(responseBody, "dummy-rpc1-module2", "module:2").find());
+ assertTrue("Xml response for /operations dummy-rpc2-module2 is incorrect",
+ validateOperationsResponseXml(responseBody, "dummy-rpc2-module2", "module:2").find());
+
+ response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ responseBody = response.readEntity(String.class);
+ assertTrue("Json response for /operations dummy-rpc1-module1 is incorrect",
+ validateOperationsResponseJson(responseBody, "dummy-rpc1-module1", "module1").find());
+ assertTrue("Json response for /operations dummy-rpc2-module1 is incorrect",
+ validateOperationsResponseJson(responseBody, "dummy-rpc2-module1", "module1").find());
+ assertTrue("Json response for /operations dummy-rpc1-module2 is incorrect",
+ validateOperationsResponseJson(responseBody, "dummy-rpc1-module2", "module2").find());
+ assertTrue("Json response for /operations dummy-rpc2-module2 is incorrect",
+ validateOperationsResponseJson(responseBody, "dummy-rpc2-module2", "module2").find());
+
+ }
+
+ // /operations/pathToMountPoint/yang-ext:mount
+ @Test
+ public void getOperationsBehindMountPointTest() throws FileNotFoundException, UnsupportedEncodingException {
+ ControllerContext controllerContext = ControllerContext.getInstance();
+ controllerContext.setGlobalSchema(schemaContextModules);
+
+ MountInstance mountInstance = mock(MountInstance.class);
+ when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint);
+ MountService mockMountService = mock(MountService.class);
+ when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
+
+ controllerContext.setMountService(mockMountService);
+
+ String uri = createUri("/operations/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
+
+ Response response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ String responseBody = response.readEntity(String.class);
+ assertTrue("Xml response for /operations/mount_point rpc-behind-module1 is incorrect",
+ validateOperationsResponseXml(responseBody, "rpc-behind-module1", "module:1:behind:mount:point").find());
+ assertTrue("Xml response for /operations/mount_point rpc-behind-module2 is incorrect",
+ validateOperationsResponseXml(responseBody, "rpc-behind-module2", "module:2:behind:mount:point").find());
+
+ response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ responseBody = response.readEntity(String.class);
+ assertTrue("Json response for /operations/mount_point rpc-behind-module1 is incorrect",
+ validateOperationsResponseJson(responseBody, "rpc-behind-module1", "module1-behind-mount-point").find());
+ assertTrue("Json response for /operations/mount_point rpc-behind-module2 is incorrect",
+ validateOperationsResponseJson(responseBody, "rpc-behind-module2", "module2-behind-mount-point").find());
+
+ }
+
+ private Matcher validateOperationsResponseJson(String searchIn, String rpcName, String moduleName) {
+ StringBuilder regex = new StringBuilder();
+ regex.append("^");
+
+ regex.append(".*\\{");
+ regex.append(".*\"");
+
+ // operations prefix optional
+ regex.append("(");
+ regex.append("ietf-restconf:");
+ regex.append("|)");
+ // :operations prefix optional
+
+ regex.append("operations\"");
+ regex.append(".*:");
+ regex.append(".*\\{");
+
+ regex.append(".*\"" + moduleName);
+ regex.append(":");
+ regex.append(rpcName + "\"");
+ regex.append(".*\\[");
+ regex.append(".*null");
+ regex.append(".*\\]");
+
+ regex.append(".*\\}");
+ regex.append(".*\\}");
+
+ regex.append(".*");
+ regex.append("$");
+ Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
+ return ptrn.matcher(searchIn);
+
+ }
+
+ private Matcher validateOperationsResponseXml(String searchIn, String rpcName, String namespace) {
+ StringBuilder regex = new StringBuilder();
+
+ regex.append("^");
+
+ regex.append(".*<operations");
+ regex.append(".*xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"");
+ regex.append(".*>");
+
+ regex.append(".*<");
+ regex.append(".*" + rpcName);
+ regex.append(".*" + namespace);
+ regex.append(".*/");
+ regex.append(".*>");
+
+ regex.append(".*</operations.*");
+ regex.append(".*>");
+
+ regex.append(".*");
+ regex.append("$");
+ Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
+ return ptrn.matcher(searchIn);
+ }
+
+ // /restconf/modules/pathToMountPoint/yang-ext:mount
+ @Test
+ public void getModulesBehindMountPoint() throws FileNotFoundException, UnsupportedEncodingException {
+ ControllerContext controllerContext = ControllerContext.getInstance();
+ controllerContext.setGlobalSchema(schemaContextModules);
+
+ MountInstance mountInstance = mock(MountInstance.class);
+ when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint);
+ MountService mockMountService = mock(MountService.class);
+ when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
+
+ controllerContext.setMountService(mockMountService);
+
+ String uri = createUri("/modules/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
+
+ Response response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ String responseBody = response.readEntity(String.class);
+
+ assertTrue(
+ "module1-behind-mount-point in json wasn't found",
+ prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
+ responseBody).find());
+ assertTrue(
+ "module2-behind-mount-point in json wasn't found",
+ prepareJsonRegex("module2-behind-mount-point", "2014-02-04", "module:2:behind:mount:point",
+ responseBody).find());
+
+ response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ responseBody = response.readEntity(String.class);
+ assertTrue(
+ "module1-behind-mount-point in json wasn't found",
+ prepareXmlRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", responseBody)
+ .find());
+ assertTrue(
+ "module2-behind-mount-point in json wasn't found",
+ prepareXmlRegex("module2-behind-mount-point", "2014-02-04", "module:2:behind:mount:point", responseBody)
+ .find());
+
+ }
+
+ // /restconf/modules/module/pathToMountPoint/yang-ext:mount/moduleName/revision
+ @Test
+ public void getModuleBehindMountPoint() throws FileNotFoundException, UnsupportedEncodingException {
+ ControllerContext controllerContext = ControllerContext.getInstance();
+ controllerContext.setGlobalSchema(schemaContextModules);
+
+ MountInstance mountInstance = mock(MountInstance.class);
+ when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint);
+ MountService mockMountService = mock(MountService.class);
+ when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
+
+ controllerContext.setMountService(mockMountService);
+
+ String uri = createUri("/modules/module/",
+ "ietf-interfaces:interfaces/interface/0/yang-ext:mount/module1-behind-mount-point/2014-02-03");
+
+ Response response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ String responseBody = response.readEntity(String.class);
+
+ assertTrue(
+ "module1-behind-mount-point in json wasn't found",
+ prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
+ responseBody).find());
+ String[] split = responseBody.split("\"module\"");
+ assertEquals("\"module\" element is returned more then once",2,split.length);
+
+
+ response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ responseBody = response.readEntity(String.class);
+ assertTrue(
+ "module1-behind-mount-point in json wasn't found",
+ prepareXmlRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", responseBody)
+ .find());
+ split = responseBody.split("<module");
+ assertEquals("<module element is returned more then once",2,split.length);
+
+
+
+
+ }
+
+ private void validateModulesResponseXml(Response response) {
+ assertEquals(200, response.getStatus());
+ String responseBody = response.readEntity(String.class);
+
+ assertTrue("Module1 in xml wasn't found", prepareXmlRegex("module1", "2014-01-01", "module:1", responseBody)
+ .find());
+ assertTrue("Module2 in xml wasn't found", prepareXmlRegex("module2", "2014-01-02", "module:2", responseBody)
+ .find());
+ assertTrue("Module3 in xml wasn't found", prepareXmlRegex("module3", "2014-01-03", "module:3", responseBody)
+ .find());
+ }
+
+ private void validateModulesResponseJson(Response response) {
+ assertEquals(200, response.getStatus());
+ String responseBody = response.readEntity(String.class);
+
+ assertTrue("Module1 in json wasn't found", prepareJsonRegex("module1", "2014-01-01", "module:1", responseBody)
+ .find());
+ assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
+ .find());
+ assertTrue("Module3 in json wasn't found", prepareJsonRegex("module3", "2014-01-03", "module:3", responseBody)
+ .find());
+ }
+
+ private Matcher prepareJsonRegex(String module, String revision, String namespace, String searchIn) {
+ StringBuilder regex = new StringBuilder();
+ regex.append("^");
+
+ regex.append(".*\\{");
+ regex.append(".*\"name\"");
+ regex.append(".*:");
+ regex.append(".*\"" + module + "\",");
+
+ regex.append(".*\"revision\"");
+ regex.append(".*:");
+ regex.append(".*\"" + revision + "\",");
+
+ regex.append(".*\"namespace\"");
+ regex.append(".*:");
+ regex.append(".*\"" + namespace + "\"");
+
+ regex.append(".*\\}");
+
+ regex.append(".*");
+ regex.append("$");
+ Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
+ return ptrn.matcher(searchIn);
+
+ }
+
+ private Matcher prepareXmlRegex(String module, String revision, String namespace, String searchIn) {
+ StringBuilder regex = new StringBuilder();
+ regex.append("^");
+
+ regex.append(".*<module.*");
+ regex.append(".*>");
+
+ regex.append(".*<name>");
+ regex.append(".*" + module);
+ regex.append(".*<\\/name>");
+
+ regex.append(".*<revision>");
+ regex.append(".*" + revision);
+ regex.append(".*<\\/revision>");
+
+ regex.append(".*<namespace>");
+ regex.append(".*" + namespace);
+ regex.append(".*<\\/namespace>");
+
+ regex.append(".*<\\/module.*>");
+
+ regex.append(".*");
+ regex.append("$");
+
+ Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
+ return ptrn.matcher(searchIn);
+ }
+
+ private void prepareMockForModulesTest(ControllerContext mockedControllerContext) throws FileNotFoundException {
+ SchemaContext schemaContext = TestUtils.loadSchemaContext("/modules");
+ mockedControllerContext.setGlobalSchema(schemaContext);
+ // when(mockedControllerContext.getGlobalSchema()).thenReturn(schemaContext);
+ }
+
private int get(String uri, String mediaType) {
return target(uri).request(mediaType).get().getStatus();
}
public class RestOperationUtils {
- static final String JSON = "+json";
- static final String XML = "+xml";
+ public static final String JSON = "+json";
+ public static final String XML = "+xml";
private RestOperationUtils() {
}
- static String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException {
+ public static String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException {
return URI.create(prefix + URLEncoder.encode(encodedPart, Charsets.US_ASCII.name()).toString()).toASCIIString();
}
}
--- /dev/null
+package org.opendaylight.controller.sal.restconf.impl.websockets.client;
+
+/**
+ * Created by mbobak on 1/22/14.
+ */
+public interface IClientMessageCallback {
+
+ public void onMessageReceived(Object message);
+}
--- /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.impl.websockets.client;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.http.HttpClientCodec;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
+import io.netty.handler.codec.http.websocketx.WebSocketVersion;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URI;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketClient {
+
+ private final URI uri;
+ private Bootstrap bootstrap = new Bootstrap();;
+ private final WebSocketClientHandler clientHandler;
+ private static final Logger logger = LoggerFactory.getLogger(WebSocketClient.class);
+ private Channel clientChannel;
+ private final EventLoopGroup group = new NioEventLoopGroup();
+
+ public WebSocketClient(URI uri,IClientMessageCallback clientMessageCallback) {
+ this.uri = uri;
+ clientHandler = new WebSocketClientHandler(
+ WebSocketClientHandshakerFactory.newHandshaker(
+ uri, WebSocketVersion.V13, null, false,null),clientMessageCallback); // last null could be replaced with DefaultHttpHeaders
+ initialize();
+ }
+ private void initialize(){
+
+ String protocol = uri.getScheme();
+ if (!"http".equals(protocol)) {
+ throw new IllegalArgumentException("Unsupported protocol: " + protocol);
+ }
+
+ bootstrap.group(group)
+ .channel(NioSocketChannel.class)
+ .handler(new ChannelInitializer<SocketChannel>() {
+ @Override
+ public void initChannel(SocketChannel ch) throws Exception {
+ ChannelPipeline pipeline = ch.pipeline();
+ pipeline.addLast("http-codec", new HttpClientCodec());
+ pipeline.addLast("aggregator", new HttpObjectAggregator(8192));
+ pipeline.addLast("ws-handler", clientHandler);
+ }
+ });
+ }
+ public void connect() throws InterruptedException{
+ System.out.println("WebSocket Client connecting");
+ clientChannel = bootstrap.connect(uri.getHost(), uri.getPort()).sync().channel();
+ clientHandler.handshakeFuture().sync();
+ }
+
+ public void writeAndFlush(String message){
+ clientChannel.writeAndFlush(new TextWebSocketFrame(message));
+ }
+ public void writeAndFlush(Object message){
+ clientChannel.writeAndFlush(message);
+ }
+
+ public void ping(){
+ clientChannel.writeAndFlush(new PingWebSocketFrame(Unpooled.copiedBuffer(new byte[]{1, 2, 3, 4, 5, 6})));
+ }
+
+ public void close(String reasonText) throws InterruptedException {
+ CloseWebSocketFrame closeWebSocketFrame = new CloseWebSocketFrame(1000,reasonText);
+ clientChannel.writeAndFlush(closeWebSocketFrame);
+
+ // WebSocketClientHandler will close the connection when the server
+ // responds to the CloseWebSocketFrame.
+ clientChannel.closeFuture().sync();
+ group.shutdownGracefully();
+ }
+
+ public static void main(String[] args) throws Exception {
+ URI uri;
+ if (args.length > 0) {
+ uri = new URI(args[0]);
+ } else {
+ uri = new URI("http://192.168.1.101:8181/opendaylight-inventory:nodes");
+ }
+ IClientMessageCallback messageCallback = new ClientMessageCallback();
+ WebSocketClient webSocketClient = new WebSocketClient(uri, messageCallback);
+ webSocketClient.connect();
+
+ while (true) {
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ String input = br.readLine();
+ if (input.equals("q")) {
+ System.out.print("Would you like to close stream? (Y = yes, empty = yes)\n");
+ input = br.readLine();
+ if (input.equals("yes") || input.isEmpty()) {
+ webSocketClient.close("opendaylight-inventory:nodes");
+ break;
+ }
+ }
+ }
+ }
+
+ private static class ClientMessageCallback implements IClientMessageCallback {
+ @Override
+ public void onMessageReceived(Object message) {
+ if (message instanceof TextWebSocketFrame) {
+ logger.info("received message {}"+ ((TextWebSocketFrame)message).text());
+ }
+ }
+ }
+
+}
--- /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.impl.websockets.client;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPromise;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
+import io.netty.handler.codec.http.websocketx.WebSocketFrame;
+import io.netty.util.CharsetUtil;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> {
+
+ private static final Logger logger = LoggerFactory.getLogger(WebSocketClientHandler.class.toString());
+ private final WebSocketClientHandshaker handshaker;
+ private ChannelPromise handshakeFuture;
+ private final IClientMessageCallback messageListener;
+
+
+ public WebSocketClientHandler(WebSocketClientHandshaker handshaker,IClientMessageCallback listener) {
+ this.handshaker = handshaker;
+ this.messageListener = listener;
+ }
+
+ public ChannelFuture handshakeFuture() {
+ return handshakeFuture;
+ }
+
+ @Override
+ public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
+ handshakeFuture = ctx.newPromise();
+ }
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) throws Exception {
+ handshaker.handshake(ctx.channel());
+ }
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+ logger.info("WebSocket Client disconnected!");
+ }
+
+ @Override
+ public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
+ Channel ch = ctx.channel();
+ if (!handshaker.isHandshakeComplete()) {
+ handshaker.finishHandshake(ch, (FullHttpResponse) msg);
+ logger.info("WebSocket Client connected!");
+ handshakeFuture.setSuccess();
+ return;
+ }
+
+ if (msg instanceof FullHttpResponse) {
+ FullHttpResponse response = (FullHttpResponse) msg;
+ throw new Exception("Unexpected FullHttpResponse (getStatus=" + response.getStatus() + ", content="
+ + response.content().toString(CharsetUtil.UTF_8) + ')');
+ }
+
+ messageListener.onMessageReceived(msg);
+ WebSocketFrame frame = (WebSocketFrame) msg;
+
+ if (frame instanceof PongWebSocketFrame) {
+ logger.info("WebSocket Client received pong");
+ } else if (frame instanceof CloseWebSocketFrame) {
+ logger.info("WebSocket Client received closing");
+ ch.close();
+ }
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ cause.printStackTrace();
+
+ if (!handshakeFuture.isDone()) {
+ handshakeFuture.setFailure(cause);
+ }
+
+ ctx.close();
+ }
+}
+
--- /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.sal.restconf.impl.websockets.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.createUri;
+
+import java.io.FileNotFoundException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
+import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
+import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class RestStream extends JerseyTest {
+
+ private static BrokerFacade brokerFacade;
+ private static RestconfImpl restconfImpl;
+ private static SchemaContext schemaContextYangsIetf;
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException {
+ schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
+ ControllerContext controllerContext = ControllerContext.getInstance();
+ controllerContext.setSchemas(schemaContextYangsIetf);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.getInstance();
+ restconfImpl.setBroker(brokerFacade);
+ restconfImpl.setControllerContext(controllerContext);
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+// enable(TestProperties.LOG_TRAFFIC);
+// enable(TestProperties.DUMP_ENTITY);
+// enable(TestProperties.RECORD_LOG_LEVEL);
+// set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE,
+ StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
+ JsonToCompositeNodeProvider.INSTANCE);
+ return resourceConfig;
+ }
+
+ @Test
+ public void testCallRpcCallGet() throws UnsupportedEncodingException, InterruptedException {
+ String uri = createUri("/operations/", "sal-remote:create-data-change-event-subscription");
+ Response responseWithStreamName = post(uri, MediaType.APPLICATION_XML, getRpcInput());
+ String xmlResponse = responseWithStreamName.readEntity(String.class);
+ assertNotNull(xmlResponse);
+ assertTrue(xmlResponse.contains("<stream-name>ietf-interfaces:interfaces/ietf-interfaces:interface/eth0</stream-name>"));
+
+ uri = createUri("/streams/stream/", "ietf-interfaces:interfaces/ietf-interfaces:interface/eth0");
+ Response responseWithRedirectionUri = get(uri, MediaType.APPLICATION_XML);
+ final URI websocketServerUri = responseWithRedirectionUri.getLocation();
+ assertNotNull(websocketServerUri);
+ assertEquals(websocketServerUri.toString(), "http://localhost:8181/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0");
+ }
+
+ private Response post(String uri, String mediaType, String data) {
+ return target(uri).request(mediaType).post(Entity.entity(data, mediaType));
+ }
+
+ private Response get(String uri, String mediaType) {
+ return target(uri).request(mediaType).get();
+ }
+
+ private String getRpcInput() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<input xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote\">");
+ sb.append("<path xmlns:int=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">/int:interfaces/int:interface[int:name='eth0']</path>");
+ sb.append("</input>");
+ return sb.toString();
+ }
+
+}
--- /dev/null
+module sal-remote {
+
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote";
+ prefix "sal-remote";
+
+
+ organization "Cisco Systems, Inc.";
+ contact "Martin Bobak <mbobak@cisco.com>";
+
+ description
+ "This module contains the definition of methods related to
+ sal remote model.
+
+ Copyright (c)2013 Cisco Systems, Inc. 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";
+
+ revision "2014-01-14" {
+ description
+ "Initial revision";
+ }
+
+
+ typedef q-name {
+ type string;
+ reference
+ "http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#QName";
+ }
+
+ rpc create-data-change-event-subscription {
+ input {
+ leaf path {
+ type instance-identifier;
+ description "Subtree path. ";
+ }
+ }
+ output {
+ leaf stream-name {
+ type string;
+ description "Notification stream name.";
+ }
+ }
+ }
+
+ notification data-changed-notification {
+ description "Data change notification.";
+ list data-change-event {
+ key path;
+ leaf path {
+ type instance-identifier;
+ }
+ leaf store {
+ type enumeration {
+ enum config;
+ enum operation;
+ }
+ }
+ leaf operation {
+ type enumeration {
+ enum created;
+ enum updated;
+ enum deleted;
+ }
+ }
+ anyxml data{
+ description "DataObject ";
+ }
+ }
+ }
+
+ rpc create-notification-stream {
+ input {
+ leaf-list notifications {
+ type q-name;
+ description "Notification QNames";
+ }
+ }
+ output {
+ leaf notification-stream-identifier {
+ type string;
+ description "Unique notification stream identifier, in which notifications will be propagated";
+ }
+ }
+ }
+
+ rpc begin-transaction{
+ output{
+ anyxml data-modification-transaction{
+ description "DataModificationTransaction xml";
+ }
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+module iana-if-type {
+ namespace "urn:ietf:params:xml:ns:yang:iana-if-type";
+ prefix ianaift;
+
+ organization "IANA";
+ contact
+ " Internet Assigned Numbers Authority
+
+ Postal: ICANN
+ 4676 Admiralty Way, Suite 330
+ Marina del Rey, CA 90292
+
+ Tel: +1 310 823 9358
+ E-Mail: iana&iana.org";
+ description
+ "This YANG module defines the iana-if-type typedef, which
+ contains YANG definitions for IANA-registered interface types.
+
+ This YANG module is maintained by IANA, and reflects the
+ 'ifType definitions' registry.
+
+ The latest revision of this YANG module can be obtained from
+ the IANA web site.
+
+ Copyright (c) 2011 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-07-04 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: IANA Interface Type YANG Module";
+ }
+
+ typedef iana-if-type {
+ type enumeration {
+ enum "other" {
+ value 1;
+ description
+ "None of the following";
+ }
+ enum "regular1822" {
+ value 2;
+ }
+ enum "hdh1822" {
+ value 3;
+ }
+ enum "ddnX25" {
+ value 4;
+ }
+ enum "rfc877x25" {
+ value 5;
+ reference
+ "RFC 1382 - SNMP MIB Extension for the X.25 Packet Layer";
+ }
+ enum "ethernetCsmacd" {
+ value 6;
+ description
+ "For all ethernet-like interfaces, regardless of speed,
+ as per RFC3635.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "iso88023Csmacd" {
+ value 7;
+ status deprecated;
+ description
+ "Deprecated via RFC3635.
+ Use ethernetCsmacd(6) instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "iso88024TokenBus" {
+ value 8;
+ }
+ enum "iso88025TokenRing" {
+ value 9;
+ }
+ enum "iso88026Man" {
+ value 10;
+ }
+ enum "starLan" {
+ value 11;
+ status deprecated;
+ description
+ "Deprecated via RFC3635.
+ Use ethernetCsmacd(6) instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "proteon10Mbit" {
+ value 12;
+ }
+ enum "proteon80Mbit" {
+ value 13;
+ }
+ enum "hyperchannel" {
+ value 14;
+ }
+ enum "fddi" {
+ value 15;
+ reference
+ "RFC 1512 - FDDI Management Information Base";
+ }
+ enum "lapb" {
+ value 16;
+ reference
+ "RFC 1381 - SNMP MIB Extension for X.25 LAPB";
+ }
+ enum "sdlc" {
+ value 17;
+ }
+ enum "ds1" {
+ value 18;
+ description
+ "DS1-MIB";
+ reference
+ "RFC 4805 - Definitions of Managed Objects for the
+ DS1, J1, E1, DS2, and E2 Interface Types";
+ }
+ enum "e1" {
+ value 19;
+ status obsolete;
+ description
+ "Obsolete see DS1-MIB";
+ reference
+ "RFC 4805 - Definitions of Managed Objects for the
+ DS1, J1, E1, DS2, and E2 Interface Types";
+ }
+ enum "basicISDN" {
+ value 20;
+ description
+ "see also RFC2127";
+ }
+ enum "primaryISDN" {
+ value 21;
+ }
+ enum "propPointToPointSerial" {
+ value 22;
+ description
+ "proprietary serial";
+ }
+ enum "ppp" {
+ value 23;
+ }
+ enum "softwareLoopback" {
+ value 24;
+ }
+ enum "eon" {
+ value 25;
+ description
+ "CLNP over IP";
+ }
+ enum "ethernet3Mbit" {
+ value 26;
+ }
+ enum "nsip" {
+ value 27;
+ description
+ "XNS over IP";
+ }
+ enum "slip" {
+ value 28;
+ description
+ "generic SLIP";
+ }
+ enum "ultra" {
+ value 29;
+ description
+ "ULTRA technologies";
+ }
+ enum "ds3" {
+ value 30;
+ description
+ "DS3-MIB";
+ reference
+ "RFC 3896 - Definitions of Managed Objects for the
+ DS3/E3 Interface Type";
+ }
+ enum "sip" {
+ value 31;
+ description
+ "SMDS, coffee";
+ reference
+ "RFC 1694 - Definitions of Managed Objects for SMDS
+ Interfaces using SMIv2";
+ }
+ enum "frameRelay" {
+ value 32;
+ description
+ "DTE only.";
+ reference
+ "RFC 2115 - Management Information Base for Frame Relay
+ DTEs Using SMIv2";
+ }
+ enum "rs232" {
+ value 33;
+ reference
+ "RFC 1659 - Definitions of Managed Objects for RS-232-like
+ Hardware Devices using SMIv2";
+ }
+ enum "para" {
+ value 34;
+ description
+ "parallel-port";
+ reference
+ "RFC 1660 - Definitions of Managed Objects for
+ Parallel-printer-like Hardware Devices using
+ SMIv2";
+ }
+ enum "arcnet" {
+ value 35;
+ description
+ "arcnet";
+ }
+ enum "arcnetPlus" {
+ value 36;
+ description
+ "arcnet plus";
+ }
+ enum "atm" {
+ value 37;
+ description
+ "ATM cells";
+ }
+ enum "miox25" {
+ value 38;
+ reference
+ "RFC 1461 - SNMP MIB extension for Multiprotocol
+ Interconnect over X.25";
+ }
+ enum "sonet" {
+ value 39;
+ description
+ "SONET or SDH";
+ }
+ enum "x25ple" {
+ value 40;
+ reference
+ "RFC 2127 - ISDN Management Information Base using SMIv2";
+ }
+ enum "iso88022llc" {
+ value 41;
+ }
+ enum "localTalk" {
+ value 42;
+ }
+ enum "smdsDxi" {
+ value 43;
+ }
+ enum "frameRelayService" {
+ value 44;
+ description
+ "FRNETSERV-MIB";
+ reference
+ "RFC 2954 - Definitions of Managed Objects for Frame
+ Relay Service";
+ }
+ enum "v35" {
+ value 45;
+ }
+ enum "hssi" {
+ value 46;
+ }
+ enum "hippi" {
+ value 47;
+ }
+ enum "modem" {
+ value 48;
+ description
+ "Generic modem";
+ }
+ enum "aal5" {
+ value 49;
+ description
+ "AAL5 over ATM";
+ }
+ enum "sonetPath" {
+ value 50;
+ }
+ enum "sonetVT" {
+ value 51;
+ }
+ enum "smdsIcip" {
+ value 52;
+ description
+ "SMDS InterCarrier Interface";
+ }
+ enum "propVirtual" {
+ value 53;
+ description
+ "proprietary virtual/internal";
+ reference
+ "RFC 2863 - The Interfaces Group MIB";
+ }
+ enum "propMultiplexor" {
+ value 54;
+ description
+ "proprietary multiplexing";
+ reference
+ "RFC 2863 - The Interfaces Group MIB";
+ }
+ enum "ieee80212" {
+ value 55;
+ description
+ "100BaseVG";
+ }
+ enum "fibreChannel" {
+ value 56;
+ description
+ "Fibre Channel";
+ }
+ enum "hippiInterface" {
+ value 57;
+ description
+ "HIPPI interfaces";
+ }
+ enum "frameRelayInterconnect" {
+ value 58;
+ status obsolete;
+ description
+ "Obsolete use either
+ frameRelay(32) or frameRelayService(44).";
+ }
+ enum "aflane8023" {
+ value 59;
+ description
+ "ATM Emulated LAN for 802.3";
+ }
+ enum "aflane8025" {
+ value 60;
+ description
+ "ATM Emulated LAN for 802.5";
+ }
+ enum "cctEmul" {
+ value 61;
+ description
+ "ATM Emulated circuit";
+ }
+ enum "fastEther" {
+ value 62;
+ status deprecated;
+ description
+ "Obsoleted via RFC3635.
+ ethernetCsmacd(6) should be used instead";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "isdn" {
+ value 63;
+ description
+ "ISDN and X.25";
+ reference
+ "RFC 1356 - Multiprotocol Interconnect on X.25 and ISDN
+ in the Packet Mode";
+ }
+ enum "v11" {
+ value 64;
+ description
+ "CCITT V.11/X.21";
+ }
+ enum "v36" {
+ value 65;
+ description
+ "CCITT V.36";
+ }
+ enum "g703at64k" {
+ value 66;
+ description
+ "CCITT G703 at 64Kbps";
+ }
+ enum "g703at2mb" {
+ value 67;
+ status obsolete;
+ description
+ "Obsolete see DS1-MIB";
+ }
+ enum "qllc" {
+ value 68;
+ description
+ "SNA QLLC";
+ }
+ enum "fastEtherFX" {
+ value 69;
+ status deprecated;
+ description
+ "Obsoleted via RFC3635
+ ethernetCsmacd(6) should be used instead";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "channel" {
+ value 70;
+ description
+ "channel";
+ }
+ enum "ieee80211" {
+ value 71;
+ description
+ "radio spread spectrum";
+ }
+ enum "ibm370parChan" {
+ value 72;
+ description
+ "IBM System 360/370 OEMI Channel";
+ }
+ enum "escon" {
+ value 73;
+ description
+ "IBM Enterprise Systems Connection";
+ }
+ enum "dlsw" {
+ value 74;
+ description
+ "Data Link Switching";
+ }
+ enum "isdns" {
+ value 75;
+ description
+ "ISDN S/T interface";
+ }
+ enum "isdnu" {
+ value 76;
+ description
+ "ISDN U interface";
+ }
+ enum "lapd" {
+ value 77;
+ description
+ "Link Access Protocol D";
+ }
+ enum "ipSwitch" {
+ value 78;
+ description
+ "IP Switching Objects";
+ }
+ enum "rsrb" {
+ value 79;
+ description
+ "Remote Source Route Bridging";
+ }
+ enum "atmLogical" {
+ value 80;
+ description
+ "ATM Logical Port";
+ reference
+ "RFC 3606 - Definitions of Supplemental Managed Objects
+ for ATM Interface";
+ }
+ enum "ds0" {
+ value 81;
+ description
+ "Digital Signal Level 0";
+ reference
+ "RFC 2494 - Definitions of Managed Objects for the DS0
+ and DS0 Bundle Interface Type";
+ }
+ enum "ds0Bundle" {
+ value 82;
+ description
+ "group of ds0s on the same ds1";
+ reference
+ "RFC 2494 - Definitions of Managed Objects for the DS0
+ and DS0 Bundle Interface Type";
+ }
+ enum "bsc" {
+ value 83;
+ description
+ "Bisynchronous Protocol";
+ }
+ enum "async" {
+ value 84;
+ description
+ "Asynchronous Protocol";
+ }
+ enum "cnr" {
+ value 85;
+ description
+ "Combat Net Radio";
+ }
+ enum "iso88025Dtr" {
+ value 86;
+ description
+ "ISO 802.5r DTR";
+ }
+ enum "eplrs" {
+ value 87;
+ description
+ "Ext Pos Loc Report Sys";
+ }
+ enum "arap" {
+ value 88;
+ description
+ "Appletalk Remote Access Protocol";
+ }
+ enum "propCnls" {
+ value 89;
+ description
+ "Proprietary Connectionless Protocol";
+ }
+ enum "hostPad" {
+ value 90;
+ description
+ "CCITT-ITU X.29 PAD Protocol";
+ }
+ enum "termPad" {
+ value 91;
+ description
+ "CCITT-ITU X.3 PAD Facility";
+ }
+ enum "frameRelayMPI" {
+ value 92;
+ description
+ "Multiproto Interconnect over FR";
+ }
+ enum "x213" {
+ value 93;
+ description
+ "CCITT-ITU X213";
+ }
+ enum "adsl" {
+ value 94;
+ description
+ "Asymmetric Digital Subscriber Loop";
+ }
+ enum "radsl" {
+ value 95;
+ description
+ "Rate-Adapt. Digital Subscriber Loop";
+ }
+ enum "sdsl" {
+ value 96;
+ description
+ "Symmetric Digital Subscriber Loop";
+ }
+ enum "vdsl" {
+ value 97;
+ description
+ "Very H-Speed Digital Subscrib. Loop";
+ }
+ enum "iso88025CRFPInt" {
+ value 98;
+ description
+ "ISO 802.5 CRFP";
+ }
+ enum "myrinet" {
+ value 99;
+ description
+ "Myricom Myrinet";
+ }
+ enum "voiceEM" {
+ value 100;
+ description
+ "voice recEive and transMit";
+ }
+ enum "voiceFXO" {
+ value 101;
+ description
+ "voice Foreign Exchange Office";
+ }
+ enum "voiceFXS" {
+ value 102;
+ description
+ "voice Foreign Exchange Station";
+ }
+ enum "voiceEncap" {
+ value 103;
+ description
+ "voice encapsulation";
+ }
+ enum "voiceOverIp" {
+ value 104;
+ description
+ "voice over IP encapsulation";
+ }
+ enum "atmDxi" {
+ value 105;
+ description
+ "ATM DXI";
+ }
+ enum "atmFuni" {
+ value 106;
+ description
+ "ATM FUNI";
+ }
+ enum "atmIma" {
+ value 107;
+ description
+ "ATM IMA";
+ }
+ enum "pppMultilinkBundle" {
+ value 108;
+ description
+ "PPP Multilink Bundle";
+ }
+ enum "ipOverCdlc" {
+ value 109;
+ description
+ "IBM ipOverCdlc";
+ }
+ enum "ipOverClaw" {
+ value 110;
+ description
+ "IBM Common Link Access to Workstn";
+ }
+ enum "stackToStack" {
+ value 111;
+ description
+ "IBM stackToStack";
+ }
+ enum "virtualIpAddress" {
+ value 112;
+ description
+ "IBM VIPA";
+ }
+ enum "mpc" {
+ value 113;
+ description
+ "IBM multi-protocol channel support";
+ }
+ enum "ipOverAtm" {
+ value 114;
+ description
+ "IBM ipOverAtm";
+ reference
+ "RFC 2320 - Definitions of Managed Objects for Classical IP
+ and ARP Over ATM Using SMIv2 (IPOA-MIB)";
+ }
+ enum "iso88025Fiber" {
+ value 115;
+ description
+ "ISO 802.5j Fiber Token Ring";
+ }
+ enum "tdlc" {
+ value 116;
+ description
+ "IBM twinaxial data link control";
+ }
+ enum "gigabitEthernet" {
+ value 117;
+ status deprecated;
+ description
+ "Obsoleted via RFC3635
+ ethernetCsmacd(6) should be used instead";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "hdlc" {
+ value 118;
+ description
+ "HDLC";
+ }
+ enum "lapf" {
+ value 119;
+ description
+ "LAP F";
+ }
+ enum "v37" {
+ value 120;
+ description
+ "V.37";
+ }
+ enum "x25mlp" {
+ value 121;
+ description
+ "Multi-Link Protocol";
+ }
+ enum "x25huntGroup" {
+ value 122;
+ description
+ "X25 Hunt Group";
+ }
+ enum "transpHdlc" {
+ value 123;
+ description
+ "Transp HDLC";
+ }
+ enum "interleave" {
+ value 124;
+ description
+ "Interleave channel";
+ }
+ enum "fast" {
+ value 125;
+ description
+ "Fast channel";
+ }
+ enum "ip" {
+ value 126;
+ description
+ "IP (for APPN HPR in IP networks)";
+ }
+ enum "docsCableMaclayer" {
+ value 127;
+ description
+ "CATV Mac Layer";
+ }
+ enum "docsCableDownstream" {
+ value 128;
+ description
+ "CATV Downstream interface";
+ }
+ enum "docsCableUpstream" {
+ value 129;
+ description
+ "CATV Upstream interface";
+ }
+ enum "a12MppSwitch" {
+ value 130;
+ description
+ "Avalon Parallel Processor";
+ }
+ enum "tunnel" {
+ value 131;
+ description
+ "Encapsulation interface";
+ }
+ enum "coffee" {
+ value 132;
+ description
+ "coffee pot";
+ reference
+ "RFC 2325 - Coffee MIB";
+ }
+ enum "ces" {
+ value 133;
+ description
+ "Circuit Emulation Service";
+ }
+ enum "atmSubInterface" {
+ value 134;
+ description
+ "ATM Sub Interface";
+ }
+ enum "l2vlan" {
+ value 135;
+ description
+ "Layer 2 Virtual LAN using 802.1Q";
+ }
+ enum "l3ipvlan" {
+ value 136;
+ description
+ "Layer 3 Virtual LAN using IP";
+ }
+ enum "l3ipxvlan" {
+ value 137;
+ description
+ "Layer 3 Virtual LAN using IPX";
+ }
+ enum "digitalPowerline" {
+ value 138;
+ description
+ "IP over Power Lines";
+ }
+ enum "mediaMailOverIp" {
+ value 139;
+ description
+ "Multimedia Mail over IP";
+ }
+ enum "dtm" {
+ value 140;
+ description
+ "Dynamic syncronous Transfer Mode";
+ }
+ enum "dcn" {
+ value 141;
+ description
+ "Data Communications Network";
+ }
+ enum "ipForward" {
+ value 142;
+ description
+ "IP Forwarding Interface";
+ }
+ enum "msdsl" {
+ value 143;
+ description
+ "Multi-rate Symmetric DSL";
+ }
+ enum "ieee1394" {
+ value 144;
+ description
+ "IEEE1394 High Performance Serial Bus";
+ }
+ enum "if-gsn" {
+ value 145;
+ description
+ "HIPPI-6400";
+ }
+ enum "dvbRccMacLayer" {
+ value 146;
+ description
+ "DVB-RCC MAC Layer";
+ }
+ enum "dvbRccDownstream" {
+ value 147;
+ description
+ "DVB-RCC Downstream Channel";
+ }
+ enum "dvbRccUpstream" {
+ value 148;
+ description
+ "DVB-RCC Upstream Channel";
+ }
+ enum "atmVirtual" {
+ value 149;
+ description
+ "ATM Virtual Interface";
+ }
+ enum "mplsTunnel" {
+ value 150;
+ description
+ "MPLS Tunnel Virtual Interface";
+ }
+ enum "srp" {
+ value 151;
+ description
+ "Spatial Reuse Protocol";
+ }
+ enum "voiceOverAtm" {
+ value 152;
+ description
+ "Voice Over ATM";
+ }
+ enum "voiceOverFrameRelay" {
+ value 153;
+ description
+ "Voice Over Frame Relay";
+ }
+ enum "idsl" {
+ value 154;
+ description
+ "Digital Subscriber Loop over ISDN";
+ }
+ enum "compositeLink" {
+ value 155;
+ description
+ "Avici Composite Link Interface";
+ }
+ enum "ss7SigLink" {
+ value 156;
+ description
+ "SS7 Signaling Link";
+ }
+ enum "propWirelessP2P" {
+ value 157;
+ description
+ "Prop. P2P wireless interface";
+ }
+ enum "frForward" {
+ value 158;
+ description
+ "Frame Forward Interface";
+ }
+ enum "rfc1483" {
+ value 159;
+ description
+ "Multiprotocol over ATM AAL5";
+ reference
+ "RFC 1483 - Multiprotocol Encapsulation over ATM
+ Adaptation Layer 5";
+ }
+ enum "usb" {
+ value 160;
+ description
+ "USB Interface";
+ }
+ enum "ieee8023adLag" {
+ value 161;
+ description
+ "IEEE 802.3ad Link Aggregate";
+ }
+ enum "bgppolicyaccounting" {
+ value 162;
+ description
+ "BGP Policy Accounting";
+ }
+ enum "frf16MfrBundle" {
+ value 163;
+ description
+ "FRF .16 Multilink Frame Relay";
+ }
+ enum "h323Gatekeeper" {
+ value 164;
+ description
+ "H323 Gatekeeper";
+ }
+ enum "h323Proxy" {
+ value 165;
+ description
+ "H323 Voice and Video Proxy";
+ }
+ enum "mpls" {
+ value 166;
+ description
+ "MPLS";
+ }
+ enum "mfSigLink" {
+ value 167;
+ description
+ "Multi-frequency signaling link";
+ }
+ enum "hdsl2" {
+ value 168;
+ description
+ "High Bit-Rate DSL - 2nd generation";
+ }
+ enum "shdsl" {
+ value 169;
+ description
+ "Multirate HDSL2";
+ }
+ enum "ds1FDL" {
+ value 170;
+ description
+ "Facility Data Link 4Kbps on a DS1";
+ }
+ enum "pos" {
+ value 171;
+ description
+ "Packet over SONET/SDH Interface";
+ }
+ enum "dvbAsiIn" {
+ value 172;
+ description
+ "DVB-ASI Input";
+ }
+ enum "dvbAsiOut" {
+ value 173;
+ description
+ "DVB-ASI Output";
+ }
+ enum "plc" {
+ value 174;
+ description
+ "Power Line Communtications";
+ }
+ enum "nfas" {
+ value 175;
+ description
+ "Non Facility Associated Signaling";
+ }
+ enum "tr008" {
+ value 176;
+ description
+ "TR008";
+ }
+ enum "gr303RDT" {
+ value 177;
+ description
+ "Remote Digital Terminal";
+ }
+ enum "gr303IDT" {
+ value 178;
+ description
+ "Integrated Digital Terminal";
+ }
+ enum "isup" {
+ value 179;
+ description
+ "ISUP";
+ }
+ enum "propDocsWirelessMaclayer" {
+ value 180;
+ description
+ "Cisco proprietary Maclayer";
+ }
+ enum "propDocsWirelessDownstream" {
+ value 181;
+ description
+ "Cisco proprietary Downstream";
+ }
+ enum "propDocsWirelessUpstream" {
+ value 182;
+ description
+ "Cisco proprietary Upstream";
+ }
+ enum "hiperlan2" {
+ value 183;
+ description
+ "HIPERLAN Type 2 Radio Interface";
+ }
+ enum "propBWAp2Mp" {
+ value 184;
+ description
+ "PropBroadbandWirelessAccesspt2multipt use of this value
+ for IEEE 802.16 WMAN interfaces as per IEEE Std 802.16f
+ is deprecated and ieee80216WMAN(237) should be used
+ instead.";
+ }
+ enum "sonetOverheadChannel" {
+ value 185;
+ description
+ "SONET Overhead Channel";
+ }
+ enum "digitalWrapperOverheadChannel" {
+ value 186;
+ description
+ "Digital Wrapper";
+ }
+ enum "aal2" {
+ value 187;
+ description
+ "ATM adaptation layer 2";
+ }
+ enum "radioMAC" {
+ value 188;
+ description
+ "MAC layer over radio links";
+ }
+ enum "atmRadio" {
+ value 189;
+ description
+ "ATM over radio links";
+ }
+ enum "imt" {
+ value 190;
+ description
+ "Inter Machine Trunks";
+ }
+ enum "mvl" {
+ value 191;
+ description
+ "Multiple Virtual Lines DSL";
+ }
+ enum "reachDSL" {
+ value 192;
+ description
+ "Long Reach DSL";
+ }
+ enum "frDlciEndPt" {
+ value 193;
+ description
+ "Frame Relay DLCI End Point";
+ }
+ enum "atmVciEndPt" {
+ value 194;
+ description
+ "ATM VCI End Point";
+ }
+ enum "opticalChannel" {
+ value 195;
+ description
+ "Optical Channel";
+ }
+ enum "opticalTransport" {
+ value 196;
+ description
+ "Optical Transport";
+ }
+ enum "propAtm" {
+ value 197;
+ description
+ "Proprietary ATM";
+ }
+ enum "voiceOverCable" {
+ value 198;
+ description
+ "Voice Over Cable Interface";
+ }
+ enum "infiniband" {
+ value 199;
+ description
+ "Infiniband";
+ }
+ enum "teLink" {
+ value 200;
+ description
+ "TE Link";
+ }
+ enum "q2931" {
+ value 201;
+ description
+ "Q.2931";
+ }
+ enum "virtualTg" {
+ value 202;
+ description
+ "Virtual Trunk Group";
+ }
+ enum "sipTg" {
+ value 203;
+ description
+ "SIP Trunk Group";
+ }
+ enum "sipSig" {
+ value 204;
+ description
+ "SIP Signaling";
+ }
+ enum "docsCableUpstreamChannel" {
+ value 205;
+ description
+ "CATV Upstream Channel";
+ }
+ enum "econet" {
+ value 206;
+ description
+ "Acorn Econet";
+ }
+ enum "pon155" {
+ value 207;
+ description
+ "FSAN 155Mb Symetrical PON interface";
+ }
+ enum "pon622" {
+ value 208;
+ description
+ "FSAN622Mb Symetrical PON interface";
+ }
+ enum "bridge" {
+ value 209;
+ description
+ "Transparent bridge interface";
+ }
+ enum "linegroup" {
+ value 210;
+ description
+ "Interface common to multiple lines";
+ }
+ enum "voiceEMFGD" {
+ value 211;
+ description
+ "voice E&M Feature Group D";
+ }
+ enum "voiceFGDEANA" {
+ value 212;
+ description
+ "voice FGD Exchange Access North American";
+ }
+ enum "voiceDID" {
+ value 213;
+ description
+ "voice Direct Inward Dialing";
+ }
+ enum "mpegTransport" {
+ value 214;
+ description
+ "MPEG transport interface";
+ }
+ enum "sixToFour" {
+ value 215;
+ status deprecated;
+ description
+ "6to4 interface (DEPRECATED)";
+ reference
+ "RFC 4087 - IP Tunnel MIB";
+ }
+ enum "gtp" {
+ value 216;
+ description
+ "GTP (GPRS Tunneling Protocol)";
+ }
+ enum "pdnEtherLoop1" {
+ value 217;
+ description
+ "Paradyne EtherLoop 1";
+ }
+ enum "pdnEtherLoop2" {
+ value 218;
+ description
+ "Paradyne EtherLoop 2";
+ }
+ enum "opticalChannelGroup" {
+ value 219;
+ description
+ "Optical Channel Group";
+ }
+ enum "homepna" {
+ value 220;
+ description
+ "HomePNA ITU-T G.989";
+ }
+ enum "gfp" {
+ value 221;
+ description
+ "Generic Framing Procedure (GFP)";
+ }
+ enum "ciscoISLvlan" {
+ value 222;
+ description
+ "Layer 2 Virtual LAN using Cisco ISL";
+ }
+ enum "actelisMetaLOOP" {
+ value 223;
+ description
+ "Acteleis proprietary MetaLOOP High Speed Link";
+ }
+ enum "fcipLink" {
+ value 224;
+ description
+ "FCIP Link";
+ }
+ enum "rpr" {
+ value 225;
+ description
+ "Resilient Packet Ring Interface Type";
+ }
+ enum "qam" {
+ value 226;
+ description
+ "RF Qam Interface";
+ }
+ enum "lmp" {
+ value 227;
+ description
+ "Link Management Protocol";
+ reference
+ "RFC 4327 - Link Management Protocol (LMP) Management
+ Information Base (MIB)";
+ }
+ enum "cblVectaStar" {
+ value 228;
+ description
+ "Cambridge Broadband Networks Limited VectaStar";
+ }
+ enum "docsCableMCmtsDownstream" {
+ value 229;
+ description
+ "CATV Modular CMTS Downstream Interface";
+ }
+ enum "adsl2" {
+ value 230;
+ status deprecated;
+ description
+ "Asymmetric Digital Subscriber Loop Version 2
+ (DEPRECATED/OBSOLETED - please use adsl2plus(238)
+ instead)";
+ reference
+ "RFC 4706 - Definitions of Managed Objects for Asymmetric
+ Digital Subscriber Line 2 (ADSL2)";
+ }
+ enum "macSecControlledIF" {
+ value 231;
+ description
+ "MACSecControlled";
+ }
+ enum "macSecUncontrolledIF" {
+ value 232;
+ description
+ "MACSecUncontrolled";
+ }
+ enum "aviciOpticalEther" {
+ value 233;
+ description
+ "Avici Optical Ethernet Aggregate";
+ }
+ enum "atmbond" {
+ value 234;
+ description
+ "atmbond";
+ }
+ enum "voiceFGDOS" {
+ value 235;
+ description
+ "voice FGD Operator Services";
+ }
+ enum "mocaVersion1" {
+ value 236;
+ description
+ "MultiMedia over Coax Alliance (MoCA) Interface
+ as documented in information provided privately to IANA";
+ }
+ enum "ieee80216WMAN" {
+ value 237;
+ description
+ "IEEE 802.16 WMAN interface";
+ }
+ enum "adsl2plus" {
+ value 238;
+ description
+ "Asymmetric Digital Subscriber Loop Version 2,
+ Version 2 Plus and all variants";
+ }
+ enum "dvbRcsMacLayer" {
+ value 239;
+ description
+ "DVB-RCS MAC Layer";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ enum "dvbTdm" {
+ value 240;
+ description
+ "DVB Satellite TDM";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ enum "dvbRcsTdma" {
+ value 241;
+ description
+ "DVB-RCS TDMA";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ enum "x86Laps" {
+ value 242;
+ description
+ "LAPS based on ITU-T X.86/Y.1323";
+ }
+ enum "wwanPP" {
+ value 243;
+ description
+ "3GPP WWAN";
+ }
+ enum "wwanPP2" {
+ value 244;
+ description
+ "3GPP2 WWAN";
+ }
+ enum "voiceEBS" {
+ value 245;
+ description
+ "voice P-phone EBS physical interface";
+ }
+ enum "ifPwType" {
+ value 246;
+ description
+ "Pseudowire interface type";
+ reference
+ "RFC 5601 - Pseudowire (PW) Management Information Base";
+ }
+ enum "ilan" {
+ value 247;
+ description
+ "Internal LAN on a bridge per IEEE 802.1ap";
+ }
+ enum "pip" {
+ value 248;
+ description
+ "Provider Instance Port on a bridge per IEEE 802.1ah PBB";
+ }
+ enum "aluELP" {
+ value 249;
+ description
+ "Alcatel-Lucent Ethernet Link Protection";
+ }
+ enum "gpon" {
+ value 250;
+ description
+ "Gigabit-capable passive optical networks (G-PON) as per
+ ITU-T G.948";
+ }
+ enum "vdsl2" {
+ value 251;
+ description
+ "Very high speed digital subscriber line Version 2
+ (as per ITU-T Recommendation G.993.2)";
+ reference
+ "RFC 5650 - Definitions of Managed Objects for Very High
+ Speed Digital Subscriber Line 2 (VDSL2)";
+ }
+ enum "capwapDot11Profile" {
+ value 252;
+ description
+ "WLAN Profile Interface";
+ reference
+ "RFC 5834 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Binding MIB for
+ IEEE 802.11";
+ }
+ enum "capwapDot11Bss" {
+ value 253;
+ description
+ "WLAN BSS Interface";
+ reference
+ "RFC 5834 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Binding MIB for
+ IEEE 802.11";
+ }
+ enum "capwapWtpVirtualRadio" {
+ value 254;
+ description
+ "WTP Virtual Radio Interface";
+ reference
+ "RFC 5833 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Base MIB";
+ }
+ enum "bits" {
+ value 255;
+ description
+ "bitsport";
+ }
+ enum "docsCableUpstreamRfPort" {
+ value 256;
+ description
+ "DOCSIS CATV Upstream RF Port";
+ }
+ enum "cableDownstreamRfPort" {
+ value 257;
+ description
+ "CATV downstream RF port";
+ }
+ enum "vmwareVirtualNic" {
+ value 258;
+ description
+ "VMware Virtual Network Interface";
+ }
+ enum "ieee802154" {
+ value 259;
+ description
+ "IEEE 802.15.4 WPAN interface";
+ reference
+ "IEEE 802.15.4-2006";
+ }
+ enum "otnOdu" {
+ value 260;
+ description
+ "OTN Optical Data Unit";
+ }
+ enum "otnOtu" {
+ value 261;
+ description
+ "OTN Optical channel Transport Unit";
+ }
+ enum "ifVfiType" {
+ value 262;
+ description
+ "VPLS Forwarding Instance Interface Type";
+ }
+ enum "g9981" {
+ value 263;
+ description
+ "G.998.1 bonded interface";
+ }
+ enum "g9982" {
+ value 264;
+ description
+ "G.998.2 bonded interface";
+ }
+ enum "g9983" {
+ value 265;
+ description
+ "G.998.3 bonded interface";
+ }
+ enum "aluEpon" {
+ value 266;
+ description
+ "Ethernet Passive Optical Networks (E-PON)";
+ }
+ enum "aluEponOnu" {
+ value 267;
+ description
+ "EPON Optical Network Unit";
+ }
+ enum "aluEponPhysicalUni" {
+ value 268;
+ description
+ "EPON physical User to Network interface";
+ }
+ enum "aluEponLogicalLink" {
+ value 269;
+ description
+ "The emulation of a point-to-point link over the EPON
+ layer";
+ }
+ enum "aluGponOnu" {
+ value 270;
+ description
+ "GPON Optical Network Unit";
+ reference
+ "ITU-T G.984.2";
+ }
+ enum "aluGponPhysicalUni" {
+ value 271;
+ description
+ "GPON physical User to Network interface";
+ reference
+ "ITU-T G.984.2";
+ }
+ enum "vmwareNicTeam" {
+ value 272;
+ description
+ "VMware NIC Team";
+ }
+ // value 273 reserved by IANA
+ }
+ description
+ "This data type is used as the syntax of the 'type'
+ leaf in the 'interface' list in the YANG module
+ ietf-interface.
+
+ The definition of this typedef with the
+ addition of newly assigned values is published
+ periodically by the IANA, in either the Assigned
+ Numbers RFC, or some derivative of it specific to
+ Internet Network Management number assignments. (The
+ latest arrangements can be obtained by contacting the
+ IANA.)
+
+ Requests for new values should be made to IANA via
+ email (iana&iana.org).";
+ reference
+ "IANA ifType definitions registry.
+ <http://www.iana.org/assignments/smi-numbers>";
+ }
+}
\ No newline at end of file
--- /dev/null
+ module ietf-inet-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+ prefix "inet";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types for Internet addresses and related things.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of protocol field related types ***/
+
+ typedef ip-version {
+ type enumeration {
+ enum unknown {
+ value "0";
+ description
+ "An unknown or unspecified version of the Internet protocol.";
+ }
+ enum ipv4 {
+ value "1";
+ description
+ "The IPv4 protocol as defined in RFC 791.";
+ }
+ enum ipv6 {
+ value "2";
+ description
+ "The IPv6 protocol as defined in RFC 2460.";
+ }
+ }
+ description
+ "This value represents the version of the IP protocol.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetVersion textual convention of the SMIv2.";
+ reference
+ "RFC 791: Internet Protocol
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ typedef dscp {
+ type uint8 {
+ range "0..63";
+ }
+ description
+ "The dscp type represents a Differentiated Services Code-Point
+ that may be used for marking packets in a traffic stream.
+
+ In the value set and its semantics, this type is equivalent
+ to the Dscp textual convention of the SMIv2.";
+ reference
+ "RFC 3289: Management Information Base for the Differentiated
+ Services Architecture
+ RFC 2474: Definition of the Differentiated Services Field
+ (DS Field) in the IPv4 and IPv6 Headers
+ RFC 2780: IANA Allocation Guidelines For Values In
+ the Internet Protocol and Related Headers";
+ }
+
+ typedef ipv6-flow-label {
+ type uint32 {
+ range "0..1048575";
+ }
+ description
+ "The flow-label type represents flow identifier or Flow Label
+ in an IPv6 packet header that may be used to discriminate
+ traffic flows.
+
+ In the value set and its semantics, this type is equivalent
+ to the IPv6FlowLabel textual convention of the SMIv2.";
+ reference
+ "RFC 3595: Textual Conventions for IPv6 Flow Label
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+ }
+
+ typedef port-number {
+ type uint16 {
+ range "0..65535";
+ }
+ description
+ "The port-number type represents a 16-bit port number of an
+ Internet transport layer protocol such as UDP, TCP, DCCP, or
+ SCTP. Port numbers are assigned by IANA. A current list of
+ all assignments is available from <http://www.iana.org/>.
+
+ Note that the port number value zero is reserved by IANA. In
+ situations where the value zero does not make sense, it can
+ be excluded by subtyping the port-number type.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetPortNumber textual convention of the SMIv2.";
+ reference
+ "RFC 768: User Datagram Protocol
+ RFC 793: Transmission Control Protocol
+ RFC 4960: Stream Control Transmission Protocol
+ RFC 4340: Datagram Congestion Control Protocol (DCCP)
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of autonomous system related types ***/
+
+ typedef as-number {
+ type uint32;
+ description
+ "The as-number type represents autonomous system numbers
+ which identify an Autonomous System (AS). An AS is a set
+ of routers under a single technical administration, using
+ an interior gateway protocol and common metrics to route
+ packets within the AS, and using an exterior gateway
+ protocol to route packets to other ASs'. IANA maintains
+ the AS number space and has delegated large parts to the
+ regional registries.
+
+ Autonomous system numbers were originally limited to 16
+ bits. BGP extensions have enlarged the autonomous system
+ number space to 32 bits. This type therefore uses an uint32
+ base type without a range restriction in order to support
+ a larger autonomous system number space.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetAutonomousSystemNumber textual convention of
+ the SMIv2.";
+ reference
+ "RFC 1930: Guidelines for creation, selection, and registration
+ of an Autonomous System (AS)
+ RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+ RFC 4893: BGP Support for Four-octet AS Number Space
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of IP address and hostname related types ***/
+
+ typedef ip-address {
+ type union {
+ type inet:ipv4-address;
+ type inet:ipv6-address;
+ }
+ description
+ "The ip-address type represents an IP address and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-address {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '(%[\p{N}\p{L}]+)?';
+ }
+ description
+ "The ipv4-address type represents an IPv4 address in
+ dotted-quad notation. The IPv4 address may include a zone
+ index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format for the zone index is the numerical
+ format";
+ }
+
+ typedef ipv6-address {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(%[\p{N}\p{L}]+)?';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(%.+)?';
+ }
+ description
+ "The ipv6-address type represents an IPv6 address in full,
+ mixed, shortened, and shortened-mixed notation. The IPv6
+ address may include a zone index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format of IPv6 addresses uses the compressed
+ format described in RFC 4291, Section 2.2, item 2 with the
+ following additional rules: the :: substitution must be
+ applied to the longest sequence of all-zero 16-bit chunks
+ in an IPv6 address. If there is a tie, the first sequence
+ of all-zero 16-bit chunks is replaced by ::. Single
+ all-zero 16-bit chunks are not compressed. The canonical
+ format uses lowercase characters and leading zeros are
+ not allowed. The canonical format for the zone index is
+ the numerical format as described in RFC 4007, Section
+ 11.2.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture
+ RFC 4007: IPv6 Scoped Address Architecture
+ RFC 5952: A Recommendation for IPv6 Address Text Representation";
+ }
+
+ typedef ip-prefix {
+ type union {
+ type inet:ipv4-prefix;
+ type inet:ipv6-prefix;
+ }
+ description
+ "The ip-prefix type represents an IP prefix and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-prefix {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+ }
+ description
+ "The ipv4-prefix type represents an IPv4 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal to 32.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The canonical format of an IPv4 prefix has all bits of
+ the IPv4 address set to zero that are not part of the
+ IPv4 prefix.";
+ }
+
+ typedef ipv6-prefix {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(/.+)';
+ }
+ description
+ "The ipv6-prefix type represents an IPv6 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal 128.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The IPv6 address should have all bits that do not belong
+ to the prefix set to zero.
+
+ The canonical format of an IPv6 prefix has all bits of
+ the IPv6 address set to zero that are not part of the
+ IPv6 prefix. Furthermore, IPv6 address is represented
+ in the compressed format described in RFC 4291, Section
+ 2.2, item 2 with the following additional rules: the ::
+ substitution must be applied to the longest sequence of
+ all-zero 16-bit chunks in an IPv6 address. If there is
+ a tie, the first sequence of all-zero 16-bit chunks is
+ replaced by ::. Single all-zero 16-bit chunks are not
+ compressed. The canonical format uses lowercase
+ characters and leading zeros are not allowed.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture";
+ }
+
+ /*** collection of domain name and URI types ***/
+
+ typedef domain-name {
+ type string {
+ pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ + '|\.';
+ length "1..253";
+ }
+ description
+ "The domain-name type represents a DNS domain name. The
+ name SHOULD be fully qualified whenever possible.
+
+ Internet domain names are only loosely specified. Section
+ 3.5 of RFC 1034 recommends a syntax (modified in Section
+ 2.1 of RFC 1123). The pattern above is intended to allow
+ for current practice in domain name use, and some possible
+ future expansion. It is designed to hold various types of
+ domain names, including names used for A or AAAA records
+ (host names) and other records, such as SRV records. Note
+ that Internet host names have a stricter syntax (described
+ in RFC 952) than the DNS recommendations in RFCs 1034 and
+ 1123, and that systems that want to store host names in
+ schema nodes using the domain-name type are recommended to
+ adhere to this stricter standard to ensure interoperability.
+
+ The encoding of DNS names in the DNS protocol is limited
+ to 255 characters. Since the encoding consists of labels
+ prefixed by a length bytes and there is a trailing NULL
+ byte, only 253 characters can appear in the textual dotted
+ notation.
+
+ The description clause of schema nodes using the domain-name
+ type MUST describe when and how these names are resolved to
+ IP addresses. Note that the resolution of a domain-name value
+ may require to query multiple DNS records (e.g., A for IPv4
+ and AAAA for IPv6). The order of the resolution process and
+ which DNS record takes precedence can either be defined
+ explicitely or it may depend on the configuration of the
+ resolver.
+
+ Domain-name values use the US-ASCII encoding. Their canonical
+ format uses lowercase US-ASCII characters. Internationalized
+ domain names MUST be encoded in punycode as described in RFC
+ 3492";
+ reference
+ "RFC 952: DoD Internet Host Table Specification
+ RFC 1034: Domain Names - Concepts and Facilities
+ RFC 1123: Requirements for Internet Hosts -- Application
+ and Support
+ RFC 2782: A DNS RR for specifying the location of services
+ (DNS SRV)
+ RFC 3492: Punycode: A Bootstring encoding of Unicode for
+ Internationalized Domain Names in Applications
+ (IDNA)
+ RFC 5891: Internationalizing Domain Names in Applications
+ (IDNA): Protocol";
+ }
+
+ typedef host {
+ type union {
+ type inet:ip-address;
+ type inet:domain-name;
+ }
+ description
+ "The host type represents either an IP address or a DNS
+ domain name.";
+ }
+
+ typedef uri {
+ type string;
+ description
+ "The uri type represents a Uniform Resource Identifier
+ (URI) as defined by STD 66.
+
+ Objects using the uri type MUST be in US-ASCII encoding,
+ and MUST be normalized as described by RFC 3986 Sections
+ 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
+ percent-encoding is removed, and all case-insensitive
+ characters are set to lowercase except for hexadecimal
+ digits, which are normalized to uppercase as described in
+ Section 6.2.2.1.
+
+ The purpose of this normalization is to help provide
+ unique URIs. Note that this normalization is not
+ sufficient to provide uniqueness. Two URIs that are
+ textually distinct after this normalization may still be
+ equivalent.
+
+ Objects using the uri type may restrict the schemes that
+ they permit. For example, 'data:' and 'urn:' schemes
+ might not be appropriate.
+
+ A zero-length URI is not a valid URI. This can be used to
+ express 'URI absent' where required.
+
+ In the value set and its semantics, this type is equivalent
+ to the Uri SMIv2 textual convention defined in RFC 5017.";
+ reference
+ "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+ RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+ Group: Uniform Resource Identifiers (URIs), URLs,
+ and Uniform Resource Names (URNs): Clarifications
+ and Recommendations
+ RFC 5017: MIB Textual Conventions for Uniform Resource
+ Identifiers (URIs)";
+ }
+
+ }
--- /dev/null
+module ietf-interfaces {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
+ prefix if;
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+ import iana-if-type {
+ prefix ianaift;
+ }
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ WG Chair: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>";
+
+ description
+ "This module contains a collection of YANG definitions for
+ managing network interfaces.
+
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-07-04 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: A YANG Data Model for Interface Management";
+ }
+
+ /* Typedefs */
+
+ typedef interface-ref {
+ type leafref {
+ path "/if:interfaces/if:interface/if:name";
+ }
+ description
+ "This type is used by data models that need to reference
+ configured interfaces.";
+ }
+
+ typedef interface-state-ref {
+ type leafref {
+ path "/if:interfaces-state/if:interface/if:name";
+ }
+ description
+ "This type is used by data models that need to reference
+ the operationally present interfaces.";
+ }
+
+ /* Features */
+
+ feature arbitrary-names {
+ description
+ "This feature indicates that the device allows user-controlled
+ interfaces to be named arbitrarily.";
+ }
+
+ feature pre-provisioning {
+ description
+ "This feature indicates that the device supports
+ pre-provisioning of interface configuration, i.e., it is
+ possible to configure an interface whose physical interface
+ hardware is not present on the device.";
+ }
+
+ feature if-mib {
+ description
+ "This feature indicates that the device implements IF-MIB.";
+ reference
+ "RFC 2863: The Interfaces Group MIB";
+ }
+
+ /* Data nodes */
+
+ container interfaces {
+ description
+ "Interface configuration parameters.";
+
+ list interface {
+ key "name";
+
+ description
+ "The list of configured interfaces on the device.
+
+ The operational state of an interface is available in the
+ /interfaces-state/interface list. If the configuration of a
+ system-controlled interface cannot be used by the system
+ (e.g., the interface hardware present does not match the
+ interface type), then the configuration is not applied to
+ the system-controlled interface shown in the
+ /interfaces-state/interface list. If the the configuration
+ of a user-controlled interface cannot be used by the system,
+ the configured interface is not instantiated in the
+ /interfaces-state/interface list.";
+
+ leaf name {
+ type string;
+ description
+ "The name of the interface.
+
+ A device MAY restrict the allowed values for this leaf,
+ possibly depending on the type of the interface.
+
+ For system-controlled interfaces, this leaf is the
+ device-specific name of the interface. The 'config false'
+ list /interfaces-state/interface contains the currently
+ existing interfaces on the device.
+
+ If a client tries to create configuration for a
+ system-controlled interface that is not present in the
+ /interfaces-state/interface list, the server MAY reject
+ the request, if the implementation does not support
+ pre-provisioning of interfaces, or if the name refers to
+ an interface that can never exist in the system. A
+ NETCONF server MUST reply with an rpc-error with the
+ error-tag 'invalid-value' in this case.
+
+ If the device supports pre-provisioning of interface
+ configuration, the feature 'pre-provisioning' is
+ advertised.
+
+ If the device allows arbitrarily named user-controlled
+ interfaces, the feature 'arbitrary-names' is advertised.
+
+ When a configured user-controlled interface is created by
+ the system, it is instantiated with the same name in the
+ /interface-state/interface list. Since the name in that
+ list MAY be mapped to ifName by an implementation, such an
+ implementation MUST restrict the allowed values for this
+ leaf so that it matches the restrictions of ifName.
+
+ If a NETCONF server that implements this restriction is
+ sent a value that doesn't match the restriction, it MUST
+ reply with an rpc-error with the error-tag
+ 'invalid-value'.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "A textual description of the interface.
+
+ This leaf MAY be mapped to ifAlias by an implementation.
+ Such an implementation MUST restrict the allowed values
+ for this leaf so that it matches the restrictions of
+ ifAlias.
+
+ If a NETCONF server that implements this restriction is
+ sent a value that doesn't match the restriction, it MUST
+ reply with an rpc-error with the error-tag
+ 'invalid-value'.
+
+ Since ifAlias is defined to be stored in non-volatile
+ storage, the MIB implementation MUST map ifAlias to the
+ value of 'description' in the persistently stored
+ datastore.
+
+ Specifically, if the device supports ':startup', when
+ ifAlias is read the device MUST return the value of
+ 'description' in the 'startup' datastore, and when it is
+ written, it MUST be written to the 'running' and 'startup'
+ datastores. Note that it is up to the implementation if
+ it modifies this single leaf in 'startup', or if it
+ performs an implicit copy-config from 'running' to
+ 'startup'.
+
+ If the device does not support ':startup', ifAlias MUST
+ be mapped to the 'description' leaf in the 'running'
+ datastore.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAlias";
+ }
+
+ leaf type {
+ type ianaift:iana-if-type;
+ mandatory true;
+ description
+ "The type of the interface.
+
+ When an interface entry is created, a server MAY
+ initialize the type leaf with a valid value, e.g., if it
+ is possible to derive the type from the name of the
+ interface.
+
+ If a client tries to set the type of an interface to a
+ value that can never be used by the system, e.g., if the
+ type is not supported or if the type does not match the
+ name of the interface, the server MUST reject the request.
+ A NETCONF server MUST reply with an rpc-error with the
+ error-tag 'invalid-value' in this case.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifType";
+ }
+
+ leaf enabled {
+ type boolean;
+ default "true";
+ description
+ "This leaf contains the configured, desired state of the
+ interface.
+
+ Systems that implement the IF-MIB use the value of this
+ leaf in the 'running' datastore to set
+ IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
+ has been initialized, as described in RFC 2863.
+
+ Changes in this leaf in the 'running' datastore are
+ reflected in ifAdminStatus, but if ifAdminStatus is
+ changed over SNMP, this leaf is not affected.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+ }
+
+ leaf link-up-down-trap-enable {
+ if-feature if-mib;
+ type enumeration {
+ enum enabled {
+ value 1;
+ }
+ enum disabled {
+ value 2;
+ }
+ }
+ description
+ "Controls whether linkUp/linkDown SNMP notifications
+ should be generated for this interface.
+
+ If this node is not configured, the value 'enabled' is
+ operationally used by the server for interfaces which do
+ not operate on top of any other interface (i.e., there are
+ no 'lower-layer-if' entries), and 'disabled' otherwise.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifLinkUpDownTrapEnable";
+ }
+ }
+ }
+
+ container interfaces-state {
+ config false;
+ description
+ "Data nodes for the operational state of interfaces.";
+
+ list interface {
+ key "name";
+
+ description
+ "The list of interfaces on the device.
+
+ System-controlled interfaces created by the system are
+ always present in this list, whether they are configured or
+ not.";
+
+ leaf name {
+ type string;
+ description
+ "The name of the interface.
+
+ This leaf MAY be mapped to ifName by an implementation.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifName";
+ }
+
+ leaf type {
+ type ianaift:iana-if-type;
+ mandatory true;
+ description
+ "The type of the interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifType";
+ }
+
+ leaf admin-status {
+ if-feature if-mib;
+ type enumeration {
+ enum up {
+ value 1;
+ description
+ "Ready to pass packets.";
+ }
+ enum down {
+ value 2;
+ description
+ "Not ready to pass packets and not in some test mode.";
+ }
+ enum testing {
+ value 3;
+ description
+ "In some test mode.";
+ }
+ }
+ mandatory true;
+ description
+ "The desired state of the interface.
+
+ This leaf has the same read semantics as ifAdminStatus.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+ }
+
+ leaf oper-status {
+ type enumeration {
+ enum up {
+ value 1;
+ description
+ "Ready to pass packets.";
+ }
+ enum down {
+ value 2;
+ description
+ "The interface does not pass any packets.";
+ }
+ enum testing {
+ value 3;
+ description
+ "In some test mode. No operational packets can
+ be passed.";
+ }
+ enum unknown {
+ value 4;
+ description
+ "Status cannot be determined for some reason.";
+ }
+ enum dormant {
+ value 5;
+ description
+ "Waiting for some external event.";
+ }
+ enum not-present {
+ value 6;
+ description
+ "Some component (typically hardware) is missing.";
+ }
+ enum lower-layer-down {
+ value 7;
+ description
+ "Down due to state of lower-layer interface(s).";
+ }
+ }
+ mandatory true;
+ description
+ "The current operational state of the interface.
+
+ This leaf has the same semantics as ifOperStatus.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOperStatus";
+ }
+
+ leaf last-change {
+ type yang:date-and-time;
+ description
+ "The time the interface entered its current operational
+ state. If the current state was entered prior to the
+ last re-initialization of the local network management
+ subsystem, then this node is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifLastChange";
+ }
+
+ leaf if-index {
+ if-feature if-mib;
+ type int32 {
+ range "1..2147483647";
+ }
+ mandatory true;
+ description
+ "The ifIndex value for the ifEntry represented by this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifIndex";
+ }
+
+ leaf phys-address {
+ type yang:phys-address;
+ description
+ "The interface's address at its protocol sub-layer. For
+ example, for an 802.x interface, this object normally
+ contains a MAC address. The interface's media-specific
+ modules must define the bit and byte ordering and the
+ format of the value of this object. For interfaces that do
+ not have such an address (e.g., a serial line), this node
+ is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifPhysAddress";
+ }
+
+ leaf-list higher-layer-if {
+ type interface-state-ref;
+ description
+ "A list of references to interfaces layered on top of this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifStackTable";
+ }
+
+ leaf-list lower-layer-if {
+ type interface-state-ref;
+ description
+ "A list of references to interfaces layered underneath this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifStackTable";
+ }
+
+ leaf speed {
+ type yang:gauge64;
+ units "bits / second";
+ description
+ "An estimate of the interface's current bandwidth in bits
+ per second. For interfaces that do not vary in
+ bandwidth or for those where no accurate estimation can
+ be made, this node should contain the nominal bandwidth.
+ For interfaces that have no concept of bandwidth, this
+ node is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifSpeed, ifHighSpeed";
+ }
+
+ container statistics {
+ description
+ "A collection of interface-related statistics objects.";
+
+ leaf discontinuity-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time on the most recent occasion at which any one or
+ more of this interface's counters suffered a
+ discontinuity. If no such discontinuities have occurred
+ since the last re-initialization of the local management
+ subsystem, then this node contains the time the local
+ management subsystem re-initialized itself.";
+ }
+
+ leaf in-octets {
+ type yang:counter64;
+ description
+ "The total number of octets received on the interface,
+ including framing characters.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCInOctets";
+ }
+ leaf in-unicast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were not addressed to a
+ multicast or broadcast address at this sub-layer.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts";
+ }
+ leaf in-broadcast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were addressed to a broadcast
+ address at this sub-layer.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCInBroadcastPkts";
+ }
+ leaf in-multicast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were addressed to a multicast
+ address at this sub-layer. For a MAC layer protocol,
+ this includes both Group and Functional addresses.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCInMulticastPkts";
+ }
+ leaf in-discards {
+ type yang:counter32;
+ description
+ "The number of inbound packets which were chosen to be
+ discarded even though no errors had been detected to
+ prevent their being deliverable to a higher-layer
+ protocol. One possible reason for discarding such a
+ packet could be to free up buffer space.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInDiscards";
+ }
+ leaf in-errors {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of inbound
+ packets that contained errors preventing them from being
+ deliverable to a higher-layer protocol. For character-
+ oriented or fixed-length interfaces, the number of
+ inbound transmission units that contained errors
+ preventing them from being deliverable to a higher-layer
+ protocol.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInErrors";
+ }
+ leaf in-unknown-protos {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of packets
+ received via the interface which were discarded because
+ of an unknown or unsupported protocol. For
+ character-oriented or fixed-length interfaces that
+ support protocol multiplexing the number of transmission
+ units received via the interface which were discarded
+ because of an unknown or unsupported protocol. For any
+ interface that does not support protocol multiplexing,
+ this counter is not present.
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos";
+ }
+
+ leaf out-octets {
+ type yang:counter64;
+ description
+ "The total number of octets transmitted out of the
+ interface, including framing characters.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCOutOctets";
+ }
+ leaf out-unicast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and which were not addressed
+ to a multicast or broadcast address at this sub-layer,
+ including those that were discarded or not sent.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts";
+ }
+ leaf out-broadcast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and which were addressed to a
+ broadcast address at this sub-layer, including those
+ that were discarded or not sent.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCOutBroadcastPkts";
+ }
+ leaf out-multicast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and which were addressed to a
+ multicast address at this sub-layer, including those
+ that were discarded or not sent. For a MAC layer
+ protocol, this includes both Group and Functional
+ addresses.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCOutMulticastPkts";
+ }
+ leaf out-discards {
+ type yang:counter32;
+ description
+ "The number of outbound packets which were chosen to be
+ discarded even though no errors had been detected to
+ prevent their being transmitted. One possible reason
+ for discarding such a packet could be to free up buffer
+ space.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOutDiscards";
+ }
+ leaf out-errors {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of outbound
+ packets that could not be transmitted because of errors.
+ For character-oriented or fixed-length interfaces, the
+ number of outbound transmission units that could not be
+ transmitted because of errors.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOutErrors";
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+module ietf-restconf {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ container modules {
+ description
+ "Contains a list of module description entries.
+ These modules are currently loaded into the server.";
+
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one module currently
+ supported by the server.";
+
+ leaf name {
+ type yang:yang-identifier;
+ description "The YANG module name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module revision date. An empty string is
+ used if no revision statement is present in the
+ YANG module.";
+ }
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server.";
+ }
+ leaf-list deviation {
+ type yang:yang-identifier;
+ description
+ "List of YANG deviation module names used by this
+ server to modify the conformance of the module
+ associated with this entry.";
+ }
+ }
+ }
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ }
\ No newline at end of file
--- /dev/null
+ module ietf-yang-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+ prefix "yang";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of counter and gauge types ***/
+
+ typedef counter32 {
+ type uint32;
+ description
+ "The counter32 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter32 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter32 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter32.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter32 {
+ type yang:counter32;
+ default "0";
+ description
+ "The zero-based-counter32 type represents a counter32
+ that has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter32 textual convention of the SMIv2.";
+ reference
+ "RFC 4502: Remote Network Monitoring Management Information
+ Base Version 2";
+ }
+
+ typedef counter64 {
+ type uint64;
+ description
+ "The counter64 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter64 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter64 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter64.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter64 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter64 {
+ type yang:counter64;
+ default "0";
+ description
+ "The zero-based-counter64 type represents a counter64 that
+ has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter64 textual convention of the SMIv2.";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ typedef gauge32 {
+ type uint32;
+ description
+ "The gauge32 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^32-1 (4294967295 decimal), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge32 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge32 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the Gauge32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef gauge64 {
+ type uint64;
+ description
+ "The gauge64 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^64-1 (18446744073709551615), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge64 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge64 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the CounterBasedGauge64 SMIv2 textual convention defined
+ in RFC 2856";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ /*** collection of identifier related types ***/
+
+ typedef object-identifier {
+ type string {
+ pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ + '(\.(0|([1-9]\d*)))*';
+ }
+ description
+ "The object-identifier type represents administratively
+ assigned names in a registration-hierarchical-name tree.
+
+ Values of this type are denoted as a sequence of numerical
+ non-negative sub-identifier values. Each sub-identifier
+ value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
+ are separated by single dots and without any intermediate
+ whitespace.
+
+ The ASN.1 standard restricts the value space of the first
+ sub-identifier to 0, 1, or 2. Furthermore, the value space
+ of the second sub-identifier is restricted to the range
+ 0 to 39 if the first sub-identifier is 0 or 1. Finally,
+ the ASN.1 standard requires that an object identifier
+ has always at least two sub-identifier. The pattern
+ captures these restrictions.
+
+ Although the number of sub-identifiers is not limited,
+ module designers should realize that there may be
+ implementations that stick with the SMIv2 limit of 128
+ sub-identifiers.
+
+ This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+ since it is not restricted to 128 sub-identifiers. Hence,
+ this type SHOULD NOT be used to represent the SMIv2 OBJECT
+ IDENTIFIER type, the object-identifier-128 type SHOULD be
+ used instead.";
+ reference
+ "ISO9834-1: Information technology -- Open Systems
+ Interconnection -- Procedures for the operation of OSI
+ Registration Authorities: General procedures and top
+ arcs of the ASN.1 Object Identifier tree";
+ }
+
+
+
+
+ typedef object-identifier-128 {
+ type object-identifier {
+ pattern '\d*(\.\d*){1,127}';
+ }
+ description
+ "This type represents object-identifiers restricted to 128
+ sub-identifiers.
+
+ In the value set and its semantics, this type is equivalent
+ to the OBJECT IDENTIFIER type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef yang-identifier {
+ type string {
+ length "1..max";
+ pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+ pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+ }
+ description
+ "A YANG identifier string as defined by the 'identifier'
+ rule in Section 12 of RFC 6020. An identifier must
+ start with an alphabetic character or an underscore
+ followed by an arbitrary sequence of alphabetic or
+ numeric characters, underscores, hyphens, or dots.
+
+ A YANG identifier MUST NOT start with any possible
+ combination of the lowercase or uppercase character
+ sequence 'xml'.";
+ reference
+ "RFC 6020: YANG - A Data Modeling Language for the Network
+ Configuration Protocol (NETCONF)";
+ }
+
+ /*** collection of date and time related types ***/
+
+ typedef date-and-time {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ + '(Z|[\+\-]\d{2}:\d{2})';
+ }
+ description
+ "The date-and-time type is a profile of the ISO 8601
+ standard for representation of dates and times using the
+ Gregorian calendar. The profile is defined by the
+ date-time production in Section 5.6 of RFC 3339.
+
+ The date-and-time type is compatible with the dateTime XML
+ schema type with the following notable exceptions:
+
+ (a) The date-and-time type does not allow negative years.
+
+ (b) The date-and-time time-offset -00:00 indicates an unknown
+ time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+ represent the same time zone in dateTime.
+
+ (c) The canonical format (see below) of data-and-time values
+ differs from the canonical format used by the dateTime XML
+ schema type, which requires all times to be in UTC using the
+ time-offset 'Z'.
+
+ This type is not equivalent to the DateAndTime textual
+ convention of the SMIv2 since RFC 3339 uses a different
+ separator between full-date and full-time and provides
+ higher resolution of time-secfrac.
+
+ The canonical format for date-and-time values with a known time
+ zone uses a numeric time zone offset that is calculated using
+ the device's configured known offset to UTC time. A change of
+ the device's offset to UTC time will cause date-and-time values
+ to change accordingly. Such changes might happen periodically
+ in case a server follows automatically daylight saving time
+ (DST) time zone offset changes. The canonical format for
+ date-and-time values with an unknown time zone (usually referring
+ to the notion of local time) uses the time-offset -00:00.";
+ reference
+ "RFC 3339: Date and Time on the Internet: Timestamps
+ RFC 2579: Textual Conventions for SMIv2
+ XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+ }
+
+ typedef timeticks {
+ type uint32;
+ description
+ "The timeticks type represents a non-negative integer that
+ represents the time, modulo 2^32 (4294967296 decimal), in
+ hundredths of a second between two epochs. When a schema
+ node is defined that uses this type, the description of
+ the schema node identifies both of the reference epochs.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeTicks type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef timestamp {
+ type yang:timeticks;
+ description
+ "The timestamp type represents the value of an associated
+ timeticks schema node at which a specific occurrence happened.
+ The specific occurrence must be defined in the description
+ of any schema node defined using this type. When the specific
+ occurrence occurred prior to the last time the associated
+ timeticks attribute was zero, then the timestamp value is
+ zero. Note that this requires all timestamp values to be
+ reset to zero when the value of the associated timeticks
+ attribute reaches 497+ days and wraps around to zero.
+
+ The associated timeticks schema node must be specified
+ in the description of any schema node using this type.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeStamp textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of generic address types ***/
+
+ typedef phys-address {
+ type string {
+ pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+ }
+ description
+ "Represents media- or physical-level addresses represented
+ as a sequence octets, each octet represented by two hexadecimal
+ numbers. Octets are separated by colons. The canonical
+ representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the PhysAddress textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ typedef mac-address {
+ type string {
+ pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+ }
+ description
+ "The mac-address type represents an IEEE 802 MAC address.
+ The canonical representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the MacAddress textual convention of the SMIv2.";
+ reference
+ "IEEE 802: IEEE Standard for Local and Metropolitan Area
+ Networks: Overview and Architecture
+ RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of XML specific types ***/
+
+ typedef xpath1.0 {
+ type string;
+ description
+ "This type represents an XPATH 1.0 expression.
+
+ When a schema node is defined that uses this type, the
+ description of the schema node MUST specify the XPath
+ context in which the XPath expression is evaluated.";
+ reference
+ "XPATH: XML Path Language (XPath) Version 1.0";
+ }
+
+ }
--- /dev/null
+module module1 {
+ namespace "module:1";
+ prefix "mod1";
+ revision "2014-01-01";
+
+ rpc dummy-rpc1-module1 {
+ }
+
+ rpc dummy-rpc2-module1 {
+ }
+
+}
\ No newline at end of file
--- /dev/null
+module module2 {
+ namespace "module:2";
+ prefix "mod2";
+ revision "2014-01-02";
+
+ rpc dummy-rpc1-module2 {
+ }
+
+ rpc dummy-rpc2-module2 {
+ }
+}
\ No newline at end of file
--- /dev/null
+module module3 {
+ namespace "module:3";
+ prefix "mod3";
+ revision "2014-01-03";
+}
\ No newline at end of file
--- /dev/null
+module module1-behind-mount-point {
+ namespace "module:1:behind:mount:point";
+ prefix "mod1bemopo";
+ revision "2014-02-03";
+
+ rpc rpc-behind-module1 {
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+module module2-behind-mount-point {
+ namespace "module:2:behind:mount:point";
+ prefix "mod2bemopo";
+ revision "2014-02-04";
+
+ rpc rpc-behind-module2 {
+ }
+
+}
\ No newline at end of file
<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>
+ <version>${yangtools.version}</version>
+ </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;
import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final RestconfClientContext restconfClientContext;
private final RestconfClientContextFactory restconfClientContextFactory = null;
- public DataBrokerServiceImpl(URL baseUrl) throws UnsupportedProtocolException {
- this.restconfClientContext = restconfClientContextFactory.getRestconfClientContext(baseUrl);
+ public DataBrokerServiceImpl(URL baseUrl, BindingIndependentMappingService mappingService, SchemaContextHolder schemaContextHolder) throws UnsupportedProtocolException {
+ this.restconfClientContext = restconfClientContextFactory.getRestconfClientContext(baseUrl, mappingService, schemaContextHolder);
}
@Override
public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
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){
+
+ }
+}
import java.util.concurrent.ExecutionException;
import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareConsumer;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
import org.opendaylight.controller.sal.binding.api.NotificationListener;
import org.opendaylight.controller.sal.binding.api.NotificationService;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
-import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
-import org.opendaylight.controller.sal.common.GlobalDataStore;
import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInputBuilder;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.osgi.framework.BundleActivator;
public void onSessionInitialized(ConsumerContext session) {
this.session = session;
NotificationService notificationService = session.getSALService(NotificationService.class);
- notificationService.addNotificationListener(ToastDone.class, this);
+ notificationService.registerNotificationListener(ToastDone.class, this);
}
@Override
import java.util.Collections;
import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger log = LoggerFactory.getLogger(ToasterProvider.class);
private ProviderContext providerContext;
- private OpendaylightToaster toaster;
+ private final OpendaylightToaster toaster;
public ToasterProvider() {
toaster = new OpendaylightToaster();
<groupId>org.eclipse.xtend</groupId>
<artifactId>org.eclipse.xtend.lib</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>${slf4j.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
--- /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 java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Utility class for comparing flows.
+ */
+final class FlowComparator {
+ private final static Logger logger = LoggerFactory.getLogger(FlowComparator.class);
+
+ private FlowComparator() {
+
+ }
+
+ public static boolean flowEquals(Flow statsFlow, Flow storedFlow) {
+ if (statsFlow.getClass() != storedFlow.getClass()) {
+ return false;
+ }
+ if (statsFlow.getContainerName()== null) {
+ if (storedFlow.getContainerName()!= null) {
+ return false;
+ }
+ } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) {
+ return false;
+ }
+ if (statsFlow.getMatch()== null) {
+ if (storedFlow.getMatch() != null) {
+ return false;
+ }
+ } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) {
+ else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) {
+ return false;
+ }
+ if (storedFlow.getPriority() == null) {
+ if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) {
+ return false;
+ }
+ } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) {
+ return false;
+ }
+ if (statsFlow.getTableId() == null) {
+ if (storedFlow.getTableId() != null) {
+ return false;
+ }
+ } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Explicit equals method to compare the 'match' for flows stored in the data-stores and flow fetched from the switch.
+ * Flow installation process has three steps
+ * 1) Store flow in config data store
+ * 2) and send it to plugin for installation
+ * 3) Flow gets installed in switch
+ *
+ * The flow user wants to install and what finally gets installed in switch can be slightly different.
+ * E.g, If user installs flow with src/dst ip=10.0.0.1/24, when it get installed in the switch
+ * src/dst ip will be changes to 10.0.0.0/24 because of netmask of 24. When statistics manager fetch
+ * stats it gets 10.0.0.0/24 rather then 10.0.0.1/24. Custom match takes care of by using masked ip
+ * while comparing two ip addresses.
+ *
+ * Sometimes when user don't provide few values that is required by flow installation request, like
+ * priority,hard timeout, idle timeout, cookies etc, plugin usages default values before sending
+ * request to the switch. So when statistics manager gets flow statistics, it gets the default value.
+ * But the flow stored in config data store don't have those defaults value. I included those checks
+ * in the customer flow/match equal function.
+ *
+ *
+ * @param statsFlow
+ * @param storedFlow
+ * @return
+ */
+ public static boolean matchEquals(Match statsFlow, Match storedFlow) {
+ if (statsFlow == storedFlow) {
+ return true;
+ }
+ if (storedFlow.getClass() != statsFlow.getClass()) {
+ return false;
+ }
+ if (storedFlow.getEthernetMatch() == null) {
+ if (statsFlow.getEthernetMatch() != null) {
+ return false;
+ }
+ } else if(!storedFlow.getEthernetMatch().equals(statsFlow.getEthernetMatch())) {
+ return false;
+ }
+ if (storedFlow.getIcmpv4Match()== null) {
+ if (statsFlow.getIcmpv4Match() != null) {
+ return false;
+ }
+ } else if(!storedFlow.getIcmpv4Match().equals(statsFlow.getIcmpv4Match())) {
+ return false;
+ }
+ if (storedFlow.getIcmpv6Match() == null) {
+ if (statsFlow.getIcmpv6Match() != null) {
+ return false;
+ }
+ } else if(!storedFlow.getIcmpv6Match().equals(statsFlow.getIcmpv6Match())) {
+ return false;
+ }
+ if (storedFlow.getInPhyPort() == null) {
+ if (statsFlow.getInPhyPort() != null) {
+ return false;
+ }
+ } else if(!storedFlow.getInPhyPort().equals(statsFlow.getInPhyPort())) {
+ return false;
+ }
+ if (storedFlow.getInPort()== null) {
+ if (statsFlow.getInPort() != null) {
+ return false;
+ }
+ } else if(!storedFlow.getInPort().equals(statsFlow.getInPort())) {
+ return false;
+ }
+ if (storedFlow.getIpMatch()== null) {
+ if (statsFlow.getIpMatch() != null) {
+ return false;
+ }
+ } else if(!storedFlow.getIpMatch().equals(statsFlow.getIpMatch())) {
+ return false;
+ }
+ if (storedFlow.getLayer3Match()== null) {
+ if (statsFlow.getLayer3Match() != null) {
+ return false;
+ }
+ } else if(!layer3MatchEquals(statsFlow.getLayer3Match(),storedFlow.getLayer3Match())) {
+ return false;
+ }
+ if (storedFlow.getLayer4Match()== null) {
+ if (statsFlow.getLayer4Match() != null) {
+ return false;
+ }
+ } else if(!storedFlow.getLayer4Match().equals(statsFlow.getLayer4Match())) {
+ return false;
+ }
+ if (storedFlow.getMetadata() == null) {
+ if (statsFlow.getMetadata() != null) {
+ return false;
+ }
+ } else if(!storedFlow.getMetadata().equals(statsFlow.getMetadata())) {
+ return false;
+ }
+ if (storedFlow.getProtocolMatchFields() == null) {
+ if (statsFlow.getProtocolMatchFields() != null) {
+ return false;
+ }
+ } else if(!storedFlow.getProtocolMatchFields().equals(statsFlow.getProtocolMatchFields())) {
+ return false;
+ }
+ if (storedFlow.getTunnel()== null) {
+ if (statsFlow.getTunnel() != null) {
+ return false;
+ }
+ } else if(!storedFlow.getTunnel().equals(statsFlow.getTunnel())) {
+ return false;
+ }
+ if (storedFlow.getVlanMatch()== null) {
+ if (statsFlow.getVlanMatch() != null) {
+ return false;
+ }
+ } else if(!storedFlow.getVlanMatch().equals(statsFlow.getVlanMatch())) {
+ return false;
+ }
+ return true;
+ }
+
+ @VisibleForTesting
+ static boolean layer3MatchEquals(Layer3Match statsLayer3Match, Layer3Match storedLayer3Match){
+ boolean verdict = true;
+ if(statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match){
+ Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match;
+ Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match;
+
+ if (verdict) {
+ verdict = compareNullSafe(
+ storedIpv4Match.getIpv4Destination(), statsIpv4Match.getIpv4Destination());
+ }
+ if (verdict) {
+ verdict = compareNullSafe(
+ statsIpv4Match.getIpv4Source(), storedIpv4Match.getIpv4Source());
+ }
+ } else {
+ Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match);
+ if (nullCheckOut != null) {
+ verdict = nullCheckOut;
+ } else {
+ verdict = storedLayer3Match.equals(statsLayer3Match);
+ }
+ }
+
+ return verdict;
+ }
+
+ private static boolean compareNullSafe(Ipv4Prefix statsIpv4, Ipv4Prefix storedIpv4) {
+ boolean verdict = true;
+ Boolean checkDestNullValuesOut = checkNullValues(storedIpv4, statsIpv4);
+ if (checkDestNullValuesOut != null) {
+ verdict = checkDestNullValuesOut;
+ } else if(!IpAddressEquals(statsIpv4, storedIpv4)){
+ verdict = false;
+ }
+
+ return verdict;
+ }
+
+ private static Boolean checkNullValues(Object v1, Object v2) {
+ Boolean verdict = null;
+ if (v1 == null && v2 != null) {
+ verdict = Boolean.FALSE;
+ } else if (v1 != null && v2 == null) {
+ verdict = Boolean.FALSE;
+ } else if (v1 == null && v2 == null) {
+ verdict = Boolean.TRUE;
+ }
+
+ return verdict;
+ }
+
+ /**
+ * TODO: why don't we use the default Ipv4Prefix.equals()?
+ *
+ * @param statsIpAddress
+ * @param storedIpAddress
+ * @return true if IPv4prefixes equals
+ */
+ private static boolean IpAddressEquals(Ipv4Prefix statsIpAddress, Ipv4Prefix storedIpAddress) {
+ IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue());
+ IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue());
+
+ if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){
+ return true;
+ }
+ if(IpBasedMatch(statsIpAddressInt,storedIpAddressInt)){
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
+ return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) == (storedIpAddressInt.getIp() & storedIpAddressInt.getMask()));
+ }
+
+ private static boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
+ return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp());
+ }
+
+ /**
+ * Method return integer version of ip address. Converted int will be mask if
+ * mask specified
+ */
+ private static IntegerIpAddress StrIpToIntIp(String ipAddresss){
+
+ String[] parts = ipAddresss.split("/");
+ String ip = parts[0];
+ int prefix;
+
+ if (parts.length < 2) {
+ prefix = 32;
+ } else {
+ prefix = Integer.parseInt(parts[1]);
+ }
+
+ IntegerIpAddress integerIpAddress = null;
+ try {
+ Inet4Address addr = (Inet4Address) InetAddress.getByName(ip);
+ byte[] addrBytes = addr.getAddress();
+ int ipInt = ((addrBytes[0] & 0xFF) << 24) |
+ ((addrBytes[1] & 0xFF) << 16) |
+ ((addrBytes[2] & 0xFF) << 8) |
+ ((addrBytes[3] & 0xFF) << 0);
+
+ int mask = 0xffffffff << 32 - prefix;
+
+ integerIpAddress = new IntegerIpAddress(ipInt, mask);
+ } catch (UnknownHostException e){
+ logger.error("Failed to determine host IP address by name: {}", e.getMessage(), e);
+ }
+
+ return integerIpAddress;
+ }
+
+ private static class IntegerIpAddress{
+ int ip;
+ int mask;
+ public IntegerIpAddress(int ip, int mask) {
+ this.ip = ip;
+ this.mask = mask;
+ }
+ public int getIp() {
+ return ip;
+ }
+ public int getMask() {
+ return mask;
+ }
+ }
+}
--- /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()));
+ }
+ }
+}
+++ /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.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-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.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.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.TableKey;
-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.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.NodeGroupStatistics;
-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.GroupKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-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.NodeConnectorKey;
-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.NodeMeterConfigStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
-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.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
-
-/**
- * Main responsibility of this class to clean up all the stale statistics data
- * associated to Flow,Meter,Group,Queue.
- * @author avishnoi@in.ibm.com
- *
- */
-public class NodeStatisticsAger {
-
- private final int NUMBER_OF_WAIT_CYCLES =2;
-
- private final StatisticsProvider statisticsProvider;
-
- private final NodeKey targetNodeKey;
-
- private final Map<GroupDescStats,Date> groupDescStatsUpdate
- = new ConcurrentHashMap<GroupDescStats,Date>();
-
- private final Map<MeterConfigStats,Date> meterConfigStatsUpdate
- = new ConcurrentHashMap<MeterConfigStats,Date>();
-
- private final Map<FlowEntry,Date> flowStatsUpdate
- = new ConcurrentHashMap<FlowEntry,Date>();
-
- private final Map<QueueEntry,Date> queuesStatsUpdate
- = new ConcurrentHashMap<QueueEntry,Date>();
-
- public NodeStatisticsAger(StatisticsProvider statisticsProvider, NodeKey nodeKey){
- this.targetNodeKey = nodeKey;
- this.statisticsProvider = statisticsProvider;
- }
-
- 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 NodeStatisticsAger getOuterType() {
- return NodeStatisticsAger.this;
- }
-
- }
-
- public 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;
- }
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + getOuterType().hashCode();
- 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 (!getOuterType().equals(other.getOuterType())) {
- return false;
- }
- 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;
- }
- private NodeStatisticsAger getOuterType() {
- return NodeStatisticsAger.this;
- }
- }
-
- public NodeKey getTargetNodeKey() {
- return targetNodeKey;
- }
-
- public Map<GroupDescStats, Date> getGroupDescStatsUpdate() {
- return groupDescStatsUpdate;
- }
-
- public Map<MeterConfigStats, Date> getMeterConfigStatsUpdate() {
- return meterConfigStatsUpdate;
- }
-
- public Map<FlowEntry, Date> getFlowStatsUpdate() {
- return flowStatsUpdate;
- }
-
- public Map<QueueEntry, Date> getQueuesStatsUpdate() {
- return queuesStatsUpdate;
- }
-
- public void updateGroupDescStats(List<GroupDescStats> list){
- Date expiryTime = getExpiryTime();
- for(GroupDescStats groupDescStats : list)
- this.groupDescStatsUpdate.put(groupDescStats, expiryTime);
- }
-
- public void updateMeterConfigStats(List<MeterConfigStats> list){
- Date expiryTime = getExpiryTime();
- for(MeterConfigStats meterConfigStats: list)
- this.meterConfigStatsUpdate.put(meterConfigStats, expiryTime);
- }
-
- public void updateFlowStats(FlowEntry flowEntry){
- this.flowStatsUpdate.put(flowEntry, getExpiryTime());
- }
- public void updateQueueStats(QueueEntry queueEntry){
- this.queuesStatsUpdate.put(queueEntry, getExpiryTime());
- }
-
- private Date getExpiryTime(){
- Date expires = new Date();
- expires.setTime(expires.getTime()+StatisticsProvider.STATS_THREAD_EXECUTION_TIME*NUMBER_OF_WAIT_CYCLES);
- return expires;
- }
-
- public void cleanStaleStatistics(){
- //Clean stale statistics related to group
- for (Iterator<GroupDescStats> it = this.groupDescStatsUpdate.keySet().iterator();it.hasNext();){
- GroupDescStats groupDescStats = it.next();
- Date now = new Date();
- Date expiryTime = this.groupDescStatsUpdate.get(groupDescStats);
- if(now.after(expiryTime)){
- cleanGroupStatsFromDataStore(groupDescStats );
- it.remove();
- }
- }
-
- //Clean stale statistics related to meter
- for (Iterator<MeterConfigStats> it = this.meterConfigStatsUpdate.keySet().iterator();it.hasNext();){
- MeterConfigStats meterConfigStats = it.next();
- Date now = new Date();
- Date expiryTime = this.meterConfigStatsUpdate.get(meterConfigStats);
- if(now.after(expiryTime)){
- cleanMeterStatsFromDataStore(meterConfigStats);
- it.remove();
- }
- }
-
- //Clean stale statistics related to flow
- for (Iterator<FlowEntry> it = this.flowStatsUpdate.keySet().iterator();it.hasNext();){
- FlowEntry flowEntry = it.next();
- Date now = new Date();
- Date expiryTime = this.flowStatsUpdate.get(flowEntry);
- if(now.after(expiryTime)){
- cleanFlowStatsFromDataStore(flowEntry);
- it.remove();
- }
- }
-
- //Clean stale statistics related to queue
- for (Iterator<QueueEntry> it = this.queuesStatsUpdate.keySet().iterator();it.hasNext();){
- QueueEntry queueEntry = it.next();
- Date now = new Date();
- Date expiryTime = this.queuesStatsUpdate.get(queueEntry);
- if(now.after(expiryTime)){
- cleanQueueStatsFromDataStore(queueEntry);
- it.remove();
- }
- }
-
- }
-
- private void cleanQueueStatsFromDataStore(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();
- cleanStaleStatisticsFromDataStore(queueRef);
- }
-
- private void cleanFlowStatsFromDataStore(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();
-
- cleanStaleStatisticsFromDataStore(flowRef);
-
- }
-
- private void cleanMeterStatsFromDataStore(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();
-
- cleanStaleStatisticsFromDataStore(nodeMeterConfigStatsAugmentation);
-
- InstanceIdentifier<?> nodeMeterStatisticsAugmentation = meterRef.augmentation(NodeMeterStatistics.class).toInstance();
-
- cleanStaleStatisticsFromDataStore(nodeMeterStatisticsAugmentation);
-
- }
-
- private void cleanGroupStatsFromDataStore(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();
-
- cleanStaleStatisticsFromDataStore(nodeGroupDescStatsAugmentation);
-
- InstanceIdentifier<?> nodeGroupStatisticsAugmentation = groupRef.augmentation(NodeGroupStatistics.class).toInstance();
-
- cleanStaleStatisticsFromDataStore(nodeGroupStatisticsAugmentation);
- }
-
- private void cleanStaleStatisticsFromDataStore(InstanceIdentifier<? extends DataObject> ii){
- if(ii != null){
- DataModificationTransaction it = this.statisticsProvider.startChange();
- it.removeOperationalData(ii);
- it.commit();
- }
- }
-}
--- /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 java.util.List;
+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.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.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.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.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.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.OpendaylightGroupStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
+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.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+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.OpendaylightMeterStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
+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.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.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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * This class handles the lifecycle of per-node statistics. It receives data
+ * from StatisticsListener, stores it in the data store and keeps track of
+ * when the data should be removed.
+ *
+ * @author avishnoi@in.ibm.com
+ */
+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 MultipartMessageManager msgManager;
+ private final InstanceIdentifier<Node> targetNodeIdentifier;
+ 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 final TimerTask task = new TimerTask() {
+ @Override
+ 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;
+ }
+
+ @Override
+ public InstanceIdentifier<Node> getNodeIdentifier() {
+ return targetNodeIdentifier;
+ }
+
+ @Override
+ public NodeRef getNodeRef() {
+ return targetNodeRef;
+ }
+
+ @Override
+ public DataModificationTransaction startDataModification() {
+ return dps.beginTransaction();
+ }
+
+ public synchronized void updateGroupDescStats(TransactionAware transaction, Boolean more, List<GroupDescStats> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ groupDescStats.updateStats(list);
+ }
+ }
+
+ public synchronized void updateGroupStats(TransactionAware transaction, Boolean more, List<GroupStats> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ groupStats.updateStats(list);
+ }
+ }
+
+ public synchronized void updateMeterConfigStats(TransactionAware transaction, Boolean more, List<MeterConfigStats> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ meterConfigStats.updateStats(list);
+ }
+ }
+
+ public synchronized void updateMeterStats(TransactionAware transaction, Boolean more, List<MeterStats> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ meterStats.updateStats(list);
+ }
+ }
+
+ public synchronized void updateQueueStats(TransactionAware transaction, Boolean more, List<QueueIdAndStatisticsMap> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ queueStats.updateStats(list);
+ }
+ }
+
+ public synchronized void updateFlowTableStats(TransactionAware transaction, Boolean more, List<FlowTableAndStatisticsMap> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ flowTableStats.updateStats(list);
+ }
+ }
+
+ public synchronized void updateNodeConnectorStats(TransactionAware transaction, Boolean more, List<NodeConnectorStatisticsAndPortNumberMap> list) {
+ if (msgManager.isExpectedTransaction(transaction, more)) {
+ nodeConnectorStats.updateStats(list);
+ }
+ }
+
+ public synchronized void updateAggregateFlowStats(TransactionAware transaction, Boolean more, AggregateFlowStatistics flowStats) {
+ final Short tableId = msgManager.isExpectedTableTransaction(transaction, more);
+ if (tableId != null) {
+ 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();
+
+ AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
+ AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
+
+ aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
+
+ logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
+ aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
+
+ TableBuilder tableBuilder = new TableBuilder();
+ tableBuilder.setKey(new TableKey(tableId));
+ tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
+ trans.putOperationalData(tableRef, tableBuilder.build());
+
+ 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 = dps.beginTransaction();
+
+ final NodeBuilder nodeData = new NodeBuilder();
+ nodeData.setKey(targetNodeKey);
+
+ NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
+ GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
+ nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
+
+ //Update augmented data
+ nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
+ trans.putOperationalData(targetNodeIdentifier, nodeData.build());
+
+ // FIXME: should we be tracking this data?
+ trans.commit();
+ }
+
+ public synchronized void updateMeterFeatures(MeterFeatures features) {
+ final DataModificationTransaction trans = dps.beginTransaction();
+
+ final NodeBuilder nodeData = new NodeBuilder();
+ nodeData.setKey(targetNodeKey);
+
+ NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
+ MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
+ nodeMeterFeatures.setMeterFeatures(meterFeature.build());
+
+ //Update augmented data
+ nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
+ trans.putOperationalData(targetNodeIdentifier, nodeData.build());
+
+ // FIXME: should we be tracking this data?
+ trans.commit();
+ }
+
+ public synchronized void cleanStaleStatistics() {
+ final DataModificationTransaction trans = dps.beginTransaction();
+ final long now = System.nanoTime();
+
+ 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();
+ }
+
+ public synchronized void requestPeriodicStatistics() {
+ logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
+
+ flowTableStats.request();
+
+ // 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);
+ }
+
+ flowStats.requestAllFlowsAllTables();
+ nodeConnectorStats.request();
+ groupStats.request();
+ groupDescStats.request();
+ meterStats.request();
+ meterConfigStats.request();
+ queueStats.request();
+ }
+
+ 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);
+
+ timer.schedule(task, (long) (Math.random() * FIRST_COLLECTION_MILLIS), STATS_COLLECTION_MILLIS);
+
+ logger.debug("Statistics handler for node started with base interval {}ms", STATS_COLLECTION_MILLIS);
+
+ requestPeriodicStatistics();
+ }
+
+ @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());
+ }
+
+ @Override
+ public void registerTransaction(TransactionId id) {
+ msgManager.recordExpectedTransaction(id);
+ logger.debug("Transaction {} for node {} sent successfully", id, targetNodeKey);
+ }
+
+ @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() + ']';
+ }
+}
--- /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.statistics.rev130819.AggregateFlowStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterConfigStatsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is responsible for listening for statistics update notifications and
+ * routing them to the appropriate NodeStatisticsHandler.
+
+ * TODO: Need to add error message listener and clean-up the associated tx id
+ * if it exists in the tx-id cache.
+ * @author vishnoianil
+ */
+public class StatisticsListener implements OpendaylightGroupStatisticsListener,
+ OpendaylightMeterStatisticsListener,
+ OpendaylightFlowStatisticsListener,
+ OpendaylightPortStatisticsListener,
+ OpendaylightFlowTableStatisticsListener,
+ OpendaylightQueueStatisticsListener{
+
+ private final static Logger sucLogger = LoggerFactory.getLogger(StatisticsListener.class);
+ private final StatisticsProvider statisticsManager;
+
+ /**
+ * default ctor
+ * @param manager
+ */
+ public StatisticsListener(final StatisticsProvider manager){
+ this.statisticsManager = manager;
+ }
+
+ @Override
+ public void onMeterConfigStatsUpdated(final MeterConfigStatsUpdated notification) {
+ final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
+ if (handler != null) {
+ handler.updateMeterConfigStats(notification, notification.isMoreReplies(), notification.getMeterConfigStats());
+ }
+ }
+
+ @Override
+ public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) {
+ final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
+ if (handler != null) {
+ handler.updateMeterStats(notification, notification.isMoreReplies(), notification.getMeterStats());
+ }
+ }
+
+ @Override
+ public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) {
+ final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId());
+ if (handler != null) {
+ handler.updateGroupDescStats(notification, notification.isMoreReplies(), notification.getGroupDescStats());
+ }
+ }
+
+ @Override
+ public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) {
+ final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId());
+ if (handler != null) {
+ handler.updateGroupStats(notification, notification.isMoreReplies(), notification.getGroupStats());
+ }
+ }
+
+ @Override
+ public void onMeterFeaturesUpdated(MeterFeaturesUpdated notification) {
+ final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId());
+ if (sna != null) {
+ sna.updateMeterFeatures(notification);
+ }
+ }
+
+ @Override
+ public void onGroupFeaturesUpdated(GroupFeaturesUpdated notification) {
+ final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId());
+ if (sna != null) {
+ sna.updateGroupFeatures(notification);
+ }
+ }
+
+ @Override
+ public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) {
+ sucLogger.debug("Received flow stats update : {}",notification.toString());
+ final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId());
+ if (sna != null) {
+ sna.updateFlowStats(notification, notification.isMoreReplies(), notification.getFlowAndStatisticsMapList());
+ }
+ }
+
+ @Override
+ public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
+ final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
+ if (handler != null) {
+ handler.updateAggregateFlowStats(notification, notification.isMoreReplies(), notification);
+ }
+ }
+
+ @Override
+ public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
+ final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
+ if (handler != null) {
+ handler.updateNodeConnectorStats(notification, notification.isMoreReplies(), notification.getNodeConnectorStatisticsAndPortNumberMap());
+ }
+ }
+
+ @Override
+ public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
+ final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
+ if (handler != null) {
+ handler.updateFlowTableStats(notification, notification.isMoreReplies(), notification.getFlowTableAndStatisticsMap());
+ }
+ }
+
+ @Override
+ public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) {
+ final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
+ if (handler != null) {
+ 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;
public class StatisticsManagerActivator extends AbstractBindingAwareProvider {
+ private StatisticsProvider statsProvider;
- private static ProviderContext pSession;
-
- private static StatisticsProvider statsProvider = new StatisticsProvider();
-
@Override
public void onSessionInitiated(ProviderContext session) {
-
- pSession = session;
- DataProviderService dps = session.<DataProviderService>getSALService(DataProviderService.class);
- StatisticsManagerActivator.statsProvider.setDataService(dps);
- DataBrokerService dbs = session.<DataBrokerService>getSALService(DataBrokerService.class);
- StatisticsManagerActivator.statsProvider.setDataBrokerService(dbs);
- NotificationProviderService nps = session.<NotificationProviderService>getSALService(NotificationProviderService.class);
- StatisticsManagerActivator.statsProvider.setNotificationService(nps);
- StatisticsManagerActivator.statsProvider.start();
+ final DataProviderService dps = session.getSALService(DataProviderService.class);
+ final NotificationProviderService nps = session.getSALService(NotificationProviderService.class);
+ statsProvider = new StatisticsProvider(dps);
+ statsProvider.start(nps, session);
}
-
+
@Override
protected void stopImpl(BundleContext context) {
- StatisticsManagerActivator.statsProvider.close();
- }
-
- public static ProviderContext getProviderContext(){
- return pSession;
+ if (statsProvider != null) {
+ statsProvider.close();
+ statsProvider = null;
+ }
}
-
}
*/
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.data.DataBrokerService;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
+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;
-/**
+import com.google.common.base.Preconditions;
+
+/**
* Following are main responsibilities of the class:
- * 1) Invoke statistics request thread to send periodic statistics request to all the
- * flow capable switch connected to the controller. It sends statistics request for
- * Group,Meter,Table,Flow,Queue,Aggregate stats.
- *
- * 2) Invoke statistics ager thread, to clean up all the stale statistics data from
+ * 1) Invoke statistics request thread to send periodic statistics request to all the
+ * flow capable switch connected to the controller. It sends statistics request for
+ * Group,Meter,Table,Flow,Queue,Aggregate stats.
+ *
+ * 2) Invoke statistics ager thread, to clean up all the stale statistics data from
* operational data store.
- *
+ *
* @author avishnoi@in.ibm.com
*
*/
public class StatisticsProvider implements AutoCloseable {
+ private static final Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class);
- public final static Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class);
-
- private DataProviderService dps;
-
- private DataBrokerService dbs;
+ private final ConcurrentMap<NodeId, NodeStatisticsHandler> handlers = new ConcurrentHashMap<>();
+ private final Timer timer = new Timer("statistics-manager", true);
+ private final DataProviderService dps;
- private NotificationProviderService nps;
-
private OpendaylightGroupStatisticsService groupStatsService;
-
+
private OpendaylightMeterStatisticsService meterStatsService;
-
+
private OpendaylightFlowStatisticsService flowStatsService;
-
+
private OpendaylightPortStatisticsService portStatsService;
private OpendaylightFlowTableStatisticsService flowTableStatsService;
private OpendaylightQueueStatisticsService queueStatsService;
- private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager();
-
- private StatisticsUpdateHandler statsUpdateHandler;
-
- private Thread statisticsRequesterThread;
-
- private Thread statisticsAgerThread;
-
- private final InstanceIdentifier<Nodes> nodesIdentifier = InstanceIdentifier.builder(Nodes.class).toInstance();
-
- public static final int STATS_THREAD_EXECUTION_TIME= 15000;
- //Local caching of stats
-
- private final ConcurrentMap<NodeId,NodeStatisticsAger> statisticsCache =
- new ConcurrentHashMap<NodeId,NodeStatisticsAger>();
-
- public DataProviderService getDataService() {
- return this.dps;
- }
-
- public void setDataService(final DataProviderService dataService) {
- this.dps = dataService;
- }
-
- public DataBrokerService getDataBrokerService() {
- return this.dbs;
- }
-
- public void setDataBrokerService(final DataBrokerService dataBrokerService) {
- this.dbs = dataBrokerService;
- }
-
- public NotificationProviderService getNotificationService() {
- return this.nps;
- }
-
- public void setNotificationService(final NotificationProviderService notificationService) {
- this.nps = notificationService;
+ public StatisticsProvider(final DataProviderService dataService) {
+ this.dps = Preconditions.checkNotNull(dataService);
}
- public MultipartMessageManager getMultipartMessageManager() {
- return multipartMessageManager;
- }
+ private final StatisticsListener updateCommiter = new StatisticsListener(StatisticsProvider.this);
- private final StatisticsUpdateCommiter updateCommiter = new StatisticsUpdateCommiter(StatisticsProvider.this);
-
private Registration<NotificationListener> listenerRegistration;
-
- public void start() {
-
- NotificationProviderService nps = this.getNotificationService();
- Registration<NotificationListener> registerNotificationListener = nps.registerNotificationListener(this.updateCommiter);
- this.listenerRegistration = registerNotificationListener;
-
- statsUpdateHandler = new StatisticsUpdateHandler(StatisticsProvider.this);
-
- registerDataStoreUpdateListener(this.getDataBrokerService());
-
- // Get Group/Meter statistics service instance
- groupStatsService = StatisticsManagerActivator.getProviderContext().
- getRpcService(OpendaylightGroupStatisticsService.class);
-
- meterStatsService = StatisticsManagerActivator.getProviderContext().
- getRpcService(OpendaylightMeterStatisticsService.class);
-
- flowStatsService = StatisticsManagerActivator.getProviderContext().
- getRpcService(OpendaylightFlowStatisticsService.class);
-
- portStatsService = StatisticsManagerActivator.getProviderContext().
- getRpcService(OpendaylightPortStatisticsService.class);
- flowTableStatsService = StatisticsManagerActivator.getProviderContext().
- getRpcService(OpendaylightFlowTableStatisticsService.class);
-
- queueStatsService = StatisticsManagerActivator.getProviderContext().
- getRpcService(OpendaylightQueueStatisticsService.class);
-
- statisticsRequesterThread = new Thread( new Runnable(){
+ private ListenerRegistration<DataChangeListener> flowCapableTrackerRegistration;
- @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(NodeStatisticsAger 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);
+ public void start(final NotificationProviderService nps, final RpcConsumerRegistry rpcRegistry) {
- statisticsAgerThread.start();
-
- 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);
+ // Get Group/Meter statistics service instances
+ groupStatsService = rpcRegistry.getRpcService(OpendaylightGroupStatisticsService.class);
+ meterStatsService = rpcRegistry.getRpcService(OpendaylightMeterStatisticsService.class);
+ flowStatsService = rpcRegistry.getRpcService(OpendaylightFlowStatisticsService.class);
+ portStatsService = rpcRegistry.getRpcService(OpendaylightPortStatisticsService.class);
+ flowTableStatsService = rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class);
+ queueStatsService = rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class);
- //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();
+ // Start receiving notifications
+ this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter);
- 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 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));
- //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() {
-
- DataProviderService dps = this.getDataService();
- return dps.beginTransaction();
+ spLogger.info("Statistics Provider started.");
}
-
- private void statsRequestSender(){
-
- List<Node> targetNodes = getAllConnectedNodes();
-
- if(targetNodes == null)
- return;
-
- for (Node targetNode : targetNodes){
-
- if(targetNode.getAugmentation(FlowCapableNode.class) != null){
- sendStatisticsRequestsToNode(targetNode);
- }
+ /**
+ * Get the handler for a particular node.
+ *
+ * @param nodeId source node
+ * @return Node statistics handler for that node. Null if the statistics should
+ * not handled.
+ */
+ public final NodeStatisticsHandler getStatisticsHandler(final NodeId nodeId) {
+ Preconditions.checkNotNull(nodeId);
+ NodeStatisticsHandler handler = handlers.get(nodeId);
+ if (handler == null) {
+ spLogger.info("Attempted to get non-existing handler for {}", nodeId);
}
+ return handler;
}
-
- 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);
+
+ @Override
+ public void close() {
+ try {
+ if (this.listenerRegistration != null) {
+ this.listenerRegistration.close();
+ this.listenerRegistration = null;
}
- if(queueStatsService != null){
- sendAllQueueStatsFromAllNodeConnector (targetNodeRef);
+ if (this.flowCapableTrackerRegistration != null) {
+ this.flowCapableTrackerRegistration.close();
+ this.flowCapableTrackerRegistration = null;
}
- }catch(Exception e){
- spLogger.error("Exception occured while sending statistics requests : {}", e);
+ timer.cancel();
+ } catch (Exception e) {
+ spLogger.warn("Failed to stop Statistics Provider completely", e);
+ } finally {
+ spLogger.info("Statistics Provider stopped.");
}
}
-
-
- 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);
+ 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;
}
- }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);;
-
- }
-
- public ConcurrentMap<NodeId, NodeStatisticsAger> getStatisticsCache() {
- return statisticsCache;
- }
-
- 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());
+ 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());
}
}
- return tablesId;
}
- @SuppressWarnings("unchecked")
- private NodeId getNodeId(NodeRef nodeRef){
- InstanceIdentifier<Node> nodeII = (InstanceIdentifier<Node>) nodeRef.getValue();
- NodeKey nodeKey = InstanceIdentifier.keyOf(nodeII);
- return nodeKey.getId();
- }
-
- @SuppressWarnings("deprecation")
- @Override
- public void close(){
-
- try {
- spLogger.info("Statistics Provider stopped.");
- if (this.listenerRegistration != null) {
-
- this.listenerRegistration.close();
-
- this.statisticsRequesterThread.destroy();
-
- this.statisticsAgerThread.destroy();
-
+ 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());
}
- } catch (Throwable e) {
- throw Exceptions.sneakyThrow(e);
- }
+ }
}
-
}
+++ /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.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.List;
-import java.util.concurrent.ConcurrentMap;
-
-import org.opendaylight.controller.md.statistics.manager.NodeStatisticsAger.FlowEntry;
-import org.opendaylight.controller.md.statistics.manager.NodeStatisticsAger.QueueEntry;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
-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.AggregateFlowStatisticsUpdate;
-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.FlowsStatisticsUpdate;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener;
-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.FlowTableStatisticsUpdate;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
-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.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.rev131026.flow.Match;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated;
-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.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.OpendaylightGroupStatisticsListener;
-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.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.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.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.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.MeterConfigStatsUpdated;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated;
-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.OpendaylightMeterStatisticsListener;
-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.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.match.types.rev131026.match.Layer3Match;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
-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.NodeConnectorStatisticsUpdate;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener;
-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.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.OpendaylightQueueStatisticsListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate;
-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.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Class implement statistics manager related listener interface and augment all the
- * received statistics data to data stores.
- * TODO: Need to add error message listener and clean-up the associated tx id
- * if it exists in the tx-id cache.
- * @author vishnoianil
- *
- */
-public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsListener,
- OpendaylightMeterStatisticsListener,
- OpendaylightFlowStatisticsListener,
- OpendaylightPortStatisticsListener,
- OpendaylightFlowTableStatisticsListener,
- OpendaylightQueueStatisticsListener{
-
- public final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class);
-
- private final StatisticsProvider statisticsManager;
- private final MultipartMessageManager messageManager;
-
- private int unaccountedFlowsCounter = 1;
-
- public StatisticsUpdateCommiter(final StatisticsProvider manager){
-
- this.statisticsManager = manager;
- this.messageManager = this.statisticsManager.getMultipartMessageManager();
- }
-
- public StatisticsProvider getStatisticsManager(){
- return statisticsManager;
- }
-
- @Override
- public void onMeterConfigStatsUpdated(MeterConfigStatsUpdated notification) {
- //Check if response is for the request statistics-manager sent.
- if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
- return;
-
- NodeKey key = new NodeKey(notification.getId());
-
- //Add statistics to local cache
- ConcurrentMap<NodeId, NodeStatisticsAger> cache = this.statisticsManager.getStatisticsCache();
- if(!cache.containsKey(notification.getId())){
- cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key));
- }
- cache.get(notification.getId()).updateMeterConfigStats(notification.getMeterConfigStats());
-
- //Publish data to configuration data store
- List<MeterConfigStats> meterConfigStatsList = notification.getMeterConfigStats();
-
- for(MeterConfigStats meterConfigStats : meterConfigStatsList){
- DataModificationTransaction it = this.statisticsManager.startChange();
- MeterBuilder meterBuilder = new MeterBuilder();
- MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId());
- meterBuilder.setKey(meterKey);
-
- InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
- .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());
- it.putOperationalData(meterRef, meterBuilder.build());
- it.commit();
-
- }
- }
-
- @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;
-
- NodeKey key = new NodeKey(notification.getId());
-
- List<MeterStats> meterStatsList = notification.getMeterStats();
-
- for(MeterStats meterStats : meterStatsList){
-
- //Publish data to configuration data store
- DataModificationTransaction it = this.statisticsManager.startChange();
- MeterBuilder meterBuilder = new MeterBuilder();
- MeterKey meterKey = new MeterKey(meterStats.getMeterId());
- meterBuilder.setKey(meterKey);
-
- InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
- .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());
- it.putOperationalData(meterRef, meterBuilder.build());
- it.commit();
- }
- }
-
- @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;
-
- NodeKey key = new NodeKey(notification.getId());
-
- //Add statistics to local cache
- ConcurrentMap<NodeId, NodeStatisticsAger> cache = this.statisticsManager.getStatisticsCache();
- if(!cache.containsKey(notification.getId())){
- cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key));
- }
- cache.get(notification.getId()).updateGroupDescStats(notification.getGroupDescStats());
-
- //Publish data to configuration data store
- List<GroupDescStats> groupDescStatsList = notification.getGroupDescStats();
-
- for(GroupDescStats groupDescStats : groupDescStatsList){
- DataModificationTransaction it = this.statisticsManager.startChange();
-
- GroupBuilder groupBuilder = new GroupBuilder();
- GroupKey groupKey = new GroupKey(groupDescStats.getGroupId());
- groupBuilder.setKey(groupKey);
-
- InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
- .augmentation(FlowCapableNode.class)
- .child(Group.class,groupKey).toInstance();
-
- NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
- GroupDescBuilder stats = new GroupDescBuilder();
- stats.fieldsFrom(groupDescStats);
- groupDesc.setGroupDesc(stats.build());
-
- //Update augmented data
- groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
-
- it.putOperationalData(groupRef, groupBuilder.build());
- it.commit();
- }
- }
-
- @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;
-
- //Publish data to configuration data store
- NodeKey key = new NodeKey(notification.getId());
- List<GroupStats> groupStatsList = notification.getGroupStats();
-
- for(GroupStats groupStats : groupStatsList){
- DataModificationTransaction it = this.statisticsManager.startChange();
-
- GroupBuilder groupBuilder = new GroupBuilder();
- GroupKey groupKey = new GroupKey(groupStats.getGroupId());
- groupBuilder.setKey(groupKey);
-
- InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
- .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());
- it.putOperationalData(groupRef, groupBuilder.build());
- it.commit();
- }
- }
-
- @Override
- public void onMeterFeaturesUpdated(MeterFeaturesUpdated notification) {
-
- MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder();
- meterFeature.setMeterBandSupported(notification.getMeterBandSupported());
- meterFeature.setMeterCapabilitiesSupported(notification.getMeterCapabilitiesSupported());
- meterFeature.setMaxBands(notification.getMaxBands());
- meterFeature.setMaxColor(notification.getMaxColor());
- meterFeature.setMaxMeter(notification.getMaxMeter());
-
- //Publish data to configuration data store
- DataModificationTransaction it = this.statisticsManager.startChange();
- NodeKey key = new NodeKey(notification.getId());
- NodeRef ref = getNodeRef(key);
-
- final NodeBuilder nodeData = new NodeBuilder();
- nodeData.setKey(key);
-
- NodeMeterFeaturesBuilder nodeMeterFeatures= new NodeMeterFeaturesBuilder();
- nodeMeterFeatures.setMeterFeatures(meterFeature.build());
-
- //Update augmented data
- nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
-
- InstanceIdentifier<? extends Object> refValue = ref.getValue();
- it.putOperationalData(refValue, nodeData.build());
- it.commit();
- }
-
- @Override
- public void onGroupFeaturesUpdated(GroupFeaturesUpdated notification) {
-
- GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder();
- groupFeatures.setActions(notification.getActions());
- groupFeatures.setGroupCapabilitiesSupported(notification.getGroupCapabilitiesSupported());
- groupFeatures.setGroupTypesSupported(notification.getGroupTypesSupported());
- groupFeatures.setMaxGroups(notification.getMaxGroups());
-
- //Publish data to configuration data store
- DataModificationTransaction it = this.statisticsManager.startChange();
- NodeKey key = new NodeKey(notification.getId());
- NodeRef ref = getNodeRef(key);
-
- final NodeBuilder nodeData = new NodeBuilder();
- nodeData.setKey(key);
-
- NodeGroupFeaturesBuilder nodeGroupFeatures= new NodeGroupFeaturesBuilder();
- nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
-
- //Update augmented data
- nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
-
- InstanceIdentifier<? extends Object> refValue = ref.getValue();
- it.putOperationalData(refValue, nodeData.build());
- it.commit();
- }
-
- @Override
- public void onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
-
- //Check if response is for the request statistics-manager sent.
- if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
- return;
-
- NodeKey key = new NodeKey(notification.getId());
- sucLogger.debug("Received flow stats update : {}",notification.toString());
-
- for(FlowAndStatisticsMapList map: notification.getFlowAndStatisticsMapList()){
- short tableId = map.getTableId();
-
- DataModificationTransaction it = this.statisticsManager.startChange();
-
- 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();
-
- //Add statistics to local cache
- ConcurrentMap<NodeId, NodeStatisticsAger> cache = this.statisticsManager.getStatisticsCache();
- if(!cache.containsKey(notification.getId())){
- cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key));
- }
- NodeStatisticsAger nsa = cache.get(notification.getId());
-
- //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());
-
- sucLogger.debug("Flow : {}",flowRule.toString());
- sucLogger.debug("Statistics to augment : {}",flowStatistics.build().toString());
-
- InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
- .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
-
- Table table= (Table)it.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()){
- sucLogger.debug("Existing flow in data store : {}",existingFlow.toString());
- if(flowEquals(flowRule,existingFlow)){
- it = this.statisticsManager.startChange();
- InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
- .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());
- sucLogger.debug("Found matching flow in the datastore, augmenting statistics");
- foundOriginalFlow = true;
- // Update entry with timestamp of latest response
- flow.setKey(existingFlow.getKey());
- FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build());
- cache.get(notification.getId()).updateFlowStats(flowStatsEntry);
-
- it.putOperationalData(flowRef, flowBuilder.build());
- it.commit();
- }
- }
- }
-
- table= (Table)it.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());
- sucLogger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString());
- if(flowEquals(flowRule,existingOperationalFlow.build())){
- InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
- .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());
- sucLogger.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 = nsa.new FlowEntry(tableId,flow.build());
- cache.get(notification.getId()).updateFlowStats(flowStatsEntry);
-
- it.putOperationalData(flowRef, flowBuilder.build());
- it.commit();
- 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, key)
- .augmentation(FlowCapableNode.class)
- .child(Table.class, new TableKey(tableId))
- .child(Flow.class,newFlowKey).toInstance();
- flowBuilder.setKey(newFlowKey);
- flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
- sucLogger.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 = nsa.new FlowEntry(tableId,flow.build());
- cache.get(notification.getId()).updateFlowStats(flowStatsEntry);
-
- it.putOperationalData(flowRef, flowBuilder.build());
- it.commit();
- }
- }
- }
-
- @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;
-
- NodeKey key = new NodeKey(notification.getId());
-
- Short tableId = messageManager.getTableIdForTxId(notification.getId(),notification.getTransactionId());
- if(tableId != null){
-
- DataModificationTransaction it = this.statisticsManager.startChange();
-
- InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
- .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
-
- AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
- AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder();
- aggregateFlowStatisticsBuilder.setByteCount(notification.getByteCount());
- aggregateFlowStatisticsBuilder.setFlowCount(notification.getFlowCount());
- aggregateFlowStatisticsBuilder.setPacketCount(notification.getPacketCount());
- aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
-
- sucLogger.debug("Augment aggregate statistics: {} for table {} on Node {}",aggregateFlowStatisticsBuilder.build().toString(),tableId,key);
-
- TableBuilder tableBuilder = new TableBuilder();
- tableBuilder.setKey(new TableKey(tableId));
- tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
- it.putOperationalData(tableRef, tableBuilder.build());
- it.commit();
-
- }
- }
-
- @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;
-
- NodeKey key = new NodeKey(notification.getId());
-
- List<NodeConnectorStatisticsAndPortNumberMap> portsStats = notification.getNodeConnectorStatisticsAndPortNumberMap();
- for(NodeConnectorStatisticsAndPortNumberMap portStats : portsStats){
-
- DataModificationTransaction it = this.statisticsManager.startChange();
-
- 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, key).child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance();
-
- NodeConnector nodeConnector = (NodeConnector)it.readOperationalData(nodeConnectorRef);
-
- if(nodeConnector != null){
- sucLogger.debug("Augmenting port statistics {} to port {}",statisticsDataBuilder.build().toString(),nodeConnectorRef.toString());
- NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
- nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, statisticsDataBuilder.build());
- it.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
- it.commit();
- }
- }
- }
-
- @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;
-
- NodeKey key = new NodeKey(notification.getId());
-
- List<FlowTableAndStatisticsMap> flowTablesStatsList = notification.getFlowTableAndStatisticsMap();
- for (FlowTableAndStatisticsMap ftStats : flowTablesStatsList){
-
- DataModificationTransaction it = this.statisticsManager.startChange();
-
- InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
- .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());
-
- statisticsDataBuilder.setFlowTableStatistics(statisticsBuilder.build());
-
- sucLogger.debug("Augment flow table statistics: {} for table {} on Node {}",statisticsBuilder.build().toString(),ftStats.getTableId(),key);
-
- TableBuilder tableBuilder = new TableBuilder();
- tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue()));
- tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
- it.putOperationalData(tableRef, tableBuilder.build());
- it.commit();
- }
- }
-
- @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;
-
- NodeKey key = new NodeKey(notification.getId());
-
- //Add statistics to local cache
- ConcurrentMap<NodeId, NodeStatisticsAger> cache = this.statisticsManager.getStatisticsCache();
- if(!cache.containsKey(notification.getId())){
- cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key));
- }
-
- NodeStatisticsAger nsa = cache.get(notification.getId());
-
- List<QueueIdAndStatisticsMap> queuesStats = notification.getQueueIdAndStatisticsMap();
- for(QueueIdAndStatisticsMap swQueueStats : queuesStats){
-
- QueueEntry queueEntry = nsa.new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId());
- nsa.updateQueueStats(queueEntry);
-
- FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
-
- FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
-
- queueStatisticsBuilder.fieldsFrom(swQueueStats);
-
- queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
-
- DataModificationTransaction it = this.statisticsManager.startChange();
-
- InstanceIdentifier<Queue> queueRef
- = InstanceIdentifier.builder(Nodes.class)
- .child(Node.class, key)
- .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId()))
- .augmentation(FlowCapableNodeConnector.class)
- .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance();
-
- QueueBuilder queueBuilder = new QueueBuilder();
- queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, queueStatisticsDataBuilder.build());
- queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
-
- sucLogger.debug("Augmenting queue statistics {} of queue {} to port {}"
- ,queueStatisticsDataBuilder.build().toString(),
- swQueueStats.getQueueId(),
- swQueueStats.getNodeConnectorId());
-
- it.putOperationalData(queueRef, queueBuilder.build());
- it.commit();
-
- }
-
- }
-
- private NodeRef getNodeRef(NodeKey nodeKey){
- InstanceIdentifierBuilder<?> builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey);
- return new NodeRef(builder.toInstance());
- }
-
- public boolean flowEquals(Flow statsFlow, Flow storedFlow) {
- if (statsFlow.getClass() != storedFlow.getClass()) {
- return false;
- }
- if (statsFlow.getContainerName()== null) {
- if (storedFlow.getContainerName()!= null) {
- return false;
- }
- } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) {
- return false;
- }
- if (statsFlow.getMatch()== null) {
- if (storedFlow.getMatch() != null) {
- return false;
- }
- } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) {
- else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) {
- return false;
- }
- if (storedFlow.getPriority() == null) {
- if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) {
- return false;
- }
- } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) {
- return false;
- }
- if (statsFlow.getTableId() == null) {
- if (storedFlow.getTableId() != null) {
- return false;
- }
- } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) {
- return false;
- }
- return true;
- }
-
- /**
- * Explicit equals method to compare the 'match' for flows stored in the data-stores and flow fetched from the switch.
- * Flow installation process has three steps
- * 1) Store flow in config data store
- * 2) and send it to plugin for installation
- * 3) Flow gets installed in switch
- *
- * The flow user wants to install and what finally gets installed in switch can be slightly different.
- * E.g, If user installs flow with src/dst ip=10.0.0.1/24, when it get installed in the switch
- * src/dst ip will be changes to 10.0.0.0/24 because of netmask of 24. When statistics manager fetch
- * stats it gets 10.0.0.0/24 rather then 10.0.0.1/24. Custom match takes care of by using masked ip
- * while comparing two ip addresses.
- *
- * Sometimes when user don't provide few values that is required by flow installation request, like
- * priority,hard timeout, idle timeout, cookies etc, plugin usages default values before sending
- * request to the switch. So when statistics manager gets flow statistics, it gets the default value.
- * But the flow stored in config data store don't have those defaults value. I included those checks
- * in the customer flow/match equal function.
- *
- *
- * @param statsFlow
- * @param storedFlow
- * @return
- */
-
- public boolean matchEquals(Match statsFlow, Match storedFlow) {
- if (statsFlow == storedFlow) {
- return true;
- }
- if (storedFlow.getClass() != statsFlow.getClass()) {
- return false;
- }
- if (storedFlow.getEthernetMatch() == null) {
- if (statsFlow.getEthernetMatch() != null) {
- return false;
- }
- } else if(!storedFlow.getEthernetMatch().equals(statsFlow.getEthernetMatch())) {
- return false;
- }
- if (storedFlow.getIcmpv4Match()== null) {
- if (statsFlow.getIcmpv4Match() != null) {
- return false;
- }
- } else if(!storedFlow.getIcmpv4Match().equals(statsFlow.getIcmpv4Match())) {
- return false;
- }
- if (storedFlow.getIcmpv6Match() == null) {
- if (statsFlow.getIcmpv6Match() != null) {
- return false;
- }
- } else if(!storedFlow.getIcmpv6Match().equals(statsFlow.getIcmpv6Match())) {
- return false;
- }
- if (storedFlow.getInPhyPort() == null) {
- if (statsFlow.getInPhyPort() != null) {
- return false;
- }
- } else if(!storedFlow.getInPhyPort().equals(statsFlow.getInPhyPort())) {
- return false;
- }
- if (storedFlow.getInPort()== null) {
- if (statsFlow.getInPort() != null) {
- return false;
- }
- } else if(!storedFlow.getInPort().equals(statsFlow.getInPort())) {
- return false;
- }
- if (storedFlow.getIpMatch()== null) {
- if (statsFlow.getIpMatch() != null) {
- return false;
- }
- } else if(!storedFlow.getIpMatch().equals(statsFlow.getIpMatch())) {
- return false;
- }
- if (storedFlow.getLayer3Match()== null) {
- if (statsFlow.getLayer3Match() != null) {
- return false;
- }
- } else if(!layer3MatchEquals(statsFlow.getLayer3Match(),storedFlow.getLayer3Match())) {
- return false;
- }
- if (storedFlow.getLayer4Match()== null) {
- if (statsFlow.getLayer4Match() != null) {
- return false;
- }
- } else if(!storedFlow.getLayer4Match().equals(statsFlow.getLayer4Match())) {
- return false;
- }
- if (storedFlow.getMetadata() == null) {
- if (statsFlow.getMetadata() != null) {
- return false;
- }
- } else if(!storedFlow.getMetadata().equals(statsFlow.getMetadata())) {
- return false;
- }
- if (storedFlow.getProtocolMatchFields() == null) {
- if (statsFlow.getProtocolMatchFields() != null) {
- return false;
- }
- } else if(!storedFlow.getProtocolMatchFields().equals(statsFlow.getProtocolMatchFields())) {
- return false;
- }
- if (storedFlow.getTunnel()== null) {
- if (statsFlow.getTunnel() != null) {
- return false;
- }
- } else if(!storedFlow.getTunnel().equals(statsFlow.getTunnel())) {
- return false;
- }
- if (storedFlow.getVlanMatch()== null) {
- if (statsFlow.getVlanMatch() != null) {
- return false;
- }
- } else if(!storedFlow.getVlanMatch().equals(statsFlow.getVlanMatch())) {
- return false;
- }
- return true;
- }
-
- private boolean layer3MatchEquals(Layer3Match statsLayer3Match, Layer3Match storedLayer3Match){
-
- if(statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match){
- Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match;
- Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match;
-
- if (storedIpv4Match.getIpv4Destination()== null) {
- if (statsIpv4Match.getIpv4Destination()!= null) {
- return false;
- }
- } else if(!IpAddressEquals(statsIpv4Match.getIpv4Destination(),storedIpv4Match.getIpv4Destination())){
- return false;
- }
- if (storedIpv4Match.getIpv4Source() == null) {
- if (statsIpv4Match.getIpv4Source() != null) {
- return false;
- }
- } else if(!IpAddressEquals(statsIpv4Match.getIpv4Source(),storedIpv4Match.getIpv4Source())) {
- return false;
- }
-
- return true;
- }else{
- return storedLayer3Match.equals(statsLayer3Match);
- }
- }
-
- private boolean IpAddressEquals(Ipv4Prefix statsIpAddress, Ipv4Prefix storedIpAddress) {
- IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue());
- IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue());
-
- if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){
- return true;
- }
- if(IpBasedMatch(statsIpAddressInt,storedIpAddressInt)){
- return true;
- }
- return false;
- }
-
- private boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
- return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) == (storedIpAddressInt.getIp() & storedIpAddressInt.getMask()));
- }
-
- private boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
- return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp());
- }
-
- /*
- * Method return integer version of ip address. Converted int will be mask if
- * mask specified
- */
- private IntegerIpAddress StrIpToIntIp(String ipAddresss){
-
- String[] parts = ipAddresss.split("/");
- String ip = parts[0];
- int prefix;
-
- if (parts.length < 2) {
- prefix = 32;
- } else {
- prefix = Integer.parseInt(parts[1]);
- }
-
- Inet4Address addr =null;
- try {
- addr = (Inet4Address) InetAddress.getByName(ip);
- } catch (UnknownHostException e){}
-
- byte[] addrBytes = addr.getAddress();
- int ipInt = ((addrBytes[0] & 0xFF) << 24) |
- ((addrBytes[1] & 0xFF) << 16) |
- ((addrBytes[2] & 0xFF) << 8) |
- ((addrBytes[3] & 0xFF) << 0);
-
- int mask = 0xffffffff << 32 - prefix;
-
- return new IntegerIpAddress(ipInt, mask);
- }
-
- class IntegerIpAddress{
- int ip;
- int mask;
- public IntegerIpAddress(int ip, int mask) {
- this.ip = ip;
- this.mask = mask;
- }
- public int getIp() {
- return ip;
- }
- public int getMask() {
- return mask;
- }
- }
-}
-
+++ /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 {
-
- public final static Logger suhLogger = LoggerFactory.getLogger(StatisticsUpdateHandler.class);
-
- private final StatisticsProvider statisticsManager;
-
- public StatisticsUpdateHandler(final StatisticsProvider manager){
-
- this.statisticsManager = manager;
- }
-
- public StatisticsProvider getStatisticsManager(){
- return statisticsManager;
- }
-
- @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);
- }
- }
- }
-
- 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();
- removeAugmentedOperationalData(flowAugmentation);
- }
- if(dataObject instanceof Meter){
- InstanceIdentifier<Meter> meterII = (InstanceIdentifier<Meter>)dataObjectInstance;
-
- InstanceIdentifier<?> nodeMeterConfigStatsAugmentation =
- InstanceIdentifier.builder(meterII).augmentation(NodeMeterConfigStats.class).toInstance();
- removeAugmentedOperationalData(nodeMeterConfigStatsAugmentation);
-
- InstanceIdentifier<?> nodeMeterStatisticsAugmentation =
- InstanceIdentifier.builder(meterII).augmentation(NodeMeterStatistics.class).toInstance();
- removeAugmentedOperationalData(nodeMeterStatisticsAugmentation);
- }
-
- if(dataObject instanceof Group){
- InstanceIdentifier<Group> groupII = (InstanceIdentifier<Group>)dataObjectInstance;
-
- InstanceIdentifier<?> nodeGroupDescStatsAugmentation =
- InstanceIdentifier.builder(groupII).augmentation(NodeGroupDescStats.class).toInstance();
- removeAugmentedOperationalData(nodeGroupDescStatsAugmentation);
-
- InstanceIdentifier<?> nodeGroupStatisticsAugmentation =
- InstanceIdentifier.builder(groupII).augmentation(NodeGroupStatistics.class).toInstance();
- removeAugmentedOperationalData(nodeGroupStatisticsAugmentation);
- }
-
- if(dataObject instanceof Queue){
- InstanceIdentifier<Queue> queueII = (InstanceIdentifier<Queue>)dataObjectInstance;
-
- InstanceIdentifier<?> nodeConnectorQueueStatisticsDataAugmentation =
- InstanceIdentifier.builder(queueII).augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance();
- removeAugmentedOperationalData(nodeConnectorQueueStatisticsDataAugmentation);
- }
- }
- }
-
- private void removeAugmentedOperationalData(InstanceIdentifier<? extends DataObject> dataObjectInstance ){
- if(dataObjectInstance != null){
- DataModificationTransaction it = this.statisticsManager.startChange();
- it.removeOperationalData(dataObjectInstance);
- it.commit();
- }
- }
-}
--- /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.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class StatisticsUpdateCommiterTest {
+
+ private static final Logger LOG = LoggerFactory
+ .getLogger(StatisticsUpdateCommiterTest.class);
+
+ /**
+ * Test method for {@link org.opendaylight.controller.md.statistics.manager.StatisticsListener#layer3MatchEquals(org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match, org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match)}.
+ */
+ @Test
+ public void testLayer3MatchEquals() {
+ String[][][] matchSeeds = new String[][][] {
+ {{"10.1.2.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}},
+ {{"10.1.2.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.1.0/24"}},
+ {{"10.1.1.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}},
+ {{"10.1.1.0/24", "10.1.1.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}},
+
+ {{"10.1.1.0/24", null}, {"10.1.1.0/24", "10.1.2.0/24"}},
+ {{"10.1.1.0/24", null}, {"10.1.2.0/24", "10.1.2.0/24"}},
+ {{"10.1.1.0/24", null}, {"10.1.2.0/24", null}},
+ {{"10.1.1.0/24", null}, {"10.1.1.0/24", null}},
+
+ {{null, "10.1.1.0/24"}, {"10.1.2.0/24", "10.1.1.0/24"}},
+ {{null, "10.1.1.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}},
+ {{null, "10.1.1.0/24"}, {null, "10.1.2.0/24"}},
+ {{null, "10.1.1.0/24"}, {null, "10.1.1.0/24"}},
+
+ {{null, null}, {null, "10.1.1.0/24"}},
+ {{null, null}, {null, null}},
+ };
+
+ boolean[] matches = new boolean[] {
+ true,
+ false,
+ false,
+ false,
+
+ false,
+ false,
+ false,
+ true,
+
+ false,
+ false,
+ false,
+ true,
+
+ false,
+ true
+ };
+
+ for (int i = 0; i < matches.length; i++) {
+ checkComparisonOfL3Match(
+ matchSeeds[i][0][0], matchSeeds[i][0][1],
+ matchSeeds[i][1][0], matchSeeds[i][1][1],
+ matches[i]);
+ }
+ }
+
+ /**
+ * @param m1Source match1 - src
+ * @param m1Destination match1 - dest
+ * @param m2Source match2 - src
+ * @param msDestination match2 - dest
+ * @param matches expected match output
+ *
+ */
+ private static void checkComparisonOfL3Match(String m1Source, String m1Destination,
+ String m2Source, String msDestination, boolean matches) {
+ Ipv4Match m1Layer3 = prepareIPv4Match(m1Source, m1Destination);
+ Ipv4Match m2Layer3 = prepareIPv4Match(m2Source, msDestination);
+ boolean comparisonResult;
+ try {
+ comparisonResult = FlowComparator.layer3MatchEquals(m1Layer3, m2Layer3);
+ Assert.assertEquals("failed to compare: "+m1Layer3+" vs. "+m2Layer3,
+ matches, comparisonResult);
+ } catch (Exception e) {
+ LOG.error("failed to compare: {} vs. {}", m1Layer3, m2Layer3, e);
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ private static Ipv4Match prepareIPv4Match(String source, String destination) {
+ Ipv4MatchBuilder ipv4MatchBuilder = new Ipv4MatchBuilder();
+ if (source != null) {
+ ipv4MatchBuilder.setIpv4Source(new Ipv4Prefix(source));
+ }
+ if (destination != null) {
+ ipv4MatchBuilder.setIpv4Destination(new Ipv4Prefix(destination));
+ }
+
+ return ipv4MatchBuilder.build();
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">\r
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">\r
+\r
+ <appender name="console" class="org.apache.log4j.ConsoleAppender">\r
+ <layout class="org.apache.log4j.PatternLayout">\r
+ <param name="ConversionPattern" value="%-6p %d{HH:mm:ss.SSS} [%10.10t] %30.30c %x - %m%n" />\r
+ </layout>\r
+ </appender>\r
+\r
+ <logger name="org.opendaylight.controller.md.statistics" additivity="false">\r
+ <level value="DEBUG" />\r
+ <appender-ref ref="console" />\r
+ </logger>\r
+\r
+ <root>\r
+ <priority value="INFO" />\r
+ <appender-ref ref="console" />\r
+ </root>\r
+</log4j:configuration>\r
package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
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.TOAttribute;
import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-
public abstract class AttributeIfcSwitchStatement<T> {
protected AttributeIfc lastAttribute;
protected abstract T caseListDependeciesAttribute(ArrayType<?> openType);
private static class UnknownOpenTypeException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
public UnknownOpenTypeException(String message) {
super(message);
}
package org.opendaylight.controller.netconf.persist.impl;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import io.netty.channel.EventLoopGroup;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import javax.annotation.concurrent.Immutable;
+
import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.client.NetconfClient;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.util.NetconfUtil;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageAdditionalHeader;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
-import javax.annotation.concurrent.Immutable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
+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;
}
public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup,
- long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) {
+ long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) {
this.address = address;
this.nettyThreadGroup = nettyThreadGroup;
this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
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) {
NetconfMessage netconfMessage = netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
NetconfUtil.checkIsMessageOk(netconfMessage);
return netconfMessage;
- } catch (RuntimeException e) { // TODO: change NetconfClient#sendMessage to throw checked exceptions
+ } catch (RuntimeException | ExecutionException | InterruptedException | TimeoutException e) {
logger.debug("Error while executing netconf transaction {} to {}", request, netconfClient, e);
throw new IOException("Failed to execute netconf transaction", e);
}
}
-
// load editConfig.xml template, populate /rpc/edit-config/config with parameter
private static NetconfMessage createEditConfigMessage(Element dataElement) {
String editConfigResourcePath = "/netconfOp/editConfig.xml";
'}';
}
}
-}
\ No newline at end of file
+}
--- /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.api;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+
+import java.io.IOException;
+
+import org.opendaylight.protocol.framework.AbstractProtocolSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractNetconfSession<S extends NetconfSession, L extends NetconfSessionListener<S>> extends AbstractProtocolSession<NetconfMessage> implements NetconfSession {
+ private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSession.class);
+ private final L sessionListener;
+ private final long sessionId;
+ private boolean up = false;
+
+ protected final Channel channel;
+
+ protected AbstractNetconfSession(L sessionListener, Channel channel, long sessionId) {
+ this.sessionListener = sessionListener;
+ this.channel = channel;
+ this.sessionId = sessionId;
+ logger.debug("Session {} created", toString());
+ }
+
+ protected abstract S thisInstance();
+
+ @Override
+ public void close() {
+ channel.close();
+ up = false;
+ sessionListener.onSessionTerminated(thisInstance(), new NetconfTerminationReason("Session closed"));
+ }
+
+ @Override
+ protected void handleMessage(NetconfMessage netconfMessage) {
+ logger.debug("handling incoming message");
+ sessionListener.onMessage(thisInstance(), netconfMessage);
+ }
+
+ @Override
+ public ChannelFuture sendMessage(NetconfMessage netconfMessage) {
+ return channel.writeAndFlush(netconfMessage);
+ }
+
+ @Override
+ protected void endOfInput() {
+ logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up"
+ : "initialized");
+ if (isUp()) {
+ this.sessionListener.onSessionDown(thisInstance(), new IOException("End of input detected. Close the session."));
+ }
+ }
+
+ @Override
+ protected void sessionUp() {
+ logger.debug("Session {} up", toString());
+ sessionListener.onSessionUp(thisInstance());
+ this.up = true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("ServerNetconfSession{");
+ sb.append("sessionId=").append(sessionId);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public final boolean isUp() {
+ return up;
+ }
+
+ public final long getSessionId() {
+ return sessionId;
+ }
+}
+
package org.opendaylight.controller.netconf.api;
-import org.opendaylight.protocol.framework.DeserializerException;
-
/**
* This exception is thrown by
* {@link NetconfSessionListener#onMessage(NetconfMessage)} to indicate fatal
* communication problem after which the session should be closed.
*/
-public class NetconfDeserializerException extends DeserializerException {
+public class NetconfDeserializerException extends Exception {
private static final long serialVersionUID = 1L;
public NetconfDeserializerException(final String message) {
import java.util.Collections;
import java.util.Map;
-import org.opendaylight.protocol.framework.DocumentedException;
-
/**
* Checked exception to communicate an error that needs to be sent to the
* netconf client.
*/
-public class NetconfDocumentedException extends DocumentedException {
+public class NetconfDocumentedException extends Exception {
private static final long serialVersionUID = 1L;
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 static final long serialVersionUID = 462175939836367285L;
-
+public class NetconfMessage {
private final Document doc;
- private String additionalHeader;
-
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);
- }
}
*/
package org.opendaylight.controller.netconf.api;
-import io.netty.channel.Channel;
-import org.opendaylight.protocol.framework.AbstractProtocolSession;
-import org.opendaylight.protocol.framework.SessionListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import io.netty.channel.ChannelFuture;
-import java.io.IOException;
+import org.opendaylight.protocol.framework.ProtocolSession;
-public abstract class NetconfSession extends AbstractProtocolSession<NetconfMessage> {
- protected final Channel channel;
- private final SessionListener sessionListener;
- private final long sessionId;
- private boolean up = false;
- private static final Logger logger = LoggerFactory.getLogger(NetconfSession.class);
-
- protected NetconfSession(SessionListener sessionListener, Channel channel, long sessionId) {
- this.sessionListener = sessionListener;
- this.channel = channel;
- this.sessionId = sessionId;
- logger.debug("Session {} created", toString());
- }
- @Override
- public void close() {
- channel.close();
- up = false;
- sessionListener.onSessionTerminated(this, new NetconfTerminationReason("Session closed"));
- }
-
- @Override
- protected void handleMessage(NetconfMessage netconfMessage) {
- logger.debug("handling incoming message");
- sessionListener.onMessage(this, netconfMessage);
- }
-
- public void sendMessage(NetconfMessage netconfMessage) {
- channel.writeAndFlush(netconfMessage);
- }
-
- @Override
- protected void endOfInput() {
- logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up"
- : "initialized");
- if (isUp()) {
- this.sessionListener.onSessionDown(this, new IOException("End of input detected. Close the session."));
- }
- }
-
- @Override
- protected void sessionUp() {
- logger.debug("Session {} up", toString());
- sessionListener.onSessionUp(this);
- this.up = true;
- }
-
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("ServerNetconfSession{");
- sb.append("sessionId=").append(sessionId);
- sb.append('}');
- return sb.toString();
- }
-
- public boolean isUp() {
- return up;
- }
-
- public long getSessionId() {
- return sessionId;
- }
+public interface NetconfSession extends ProtocolSession<NetconfMessage> {
+ ChannelFuture sendMessage(NetconfMessage message);
}
-
import org.opendaylight.protocol.framework.SessionListener;
-public interface NetconfSessionListener extends
- SessionListener<NetconfMessage, NetconfSession, NetconfTerminationReason> {
+public interface NetconfSessionListener<S extends NetconfSession> extends SessionListener<NetconfMessage, S, NetconfTerminationReason> {
}
/**
* Class extending {@link NetconfClientSessionListener} to provide notification capability.
*/
-public abstract class AbstractNetconfClientNotifySessionListener extends NetconfClientSessionListener {
+public abstract class AbstractNetconfClientNotifySessionListener extends SimpleNetconfClientSessionListener {
/*
* Maybe some capabilities could be expressed as internal NetconfClientSessionListener handlers.
* It would enable NetconfClient functionality to be extended by using namespace handlers.
* @param message {@see NetconfClientSessionListener#onMessage(NetconfClientSession, NetconfMessage)}
*/
@Override
- public final synchronized void onMessage(NetconfClientSession session, NetconfMessage message) {
+ public final void onMessage(NetconfClientSession session, NetconfMessage message) {
if (isNotification(message)) {
onNotification(session, message);
} else {
package org.opendaylight.controller.netconf.client;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.Sets;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GlobalEventExecutor;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.protocol.framework.NeverReconnectStrategy;
-import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.TimedReconnectStrategy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.protocol.framework.NeverReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.TimedReconnectStrategy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Sets;
+
+/**
+ * @deprecated Use {@link NetconfClientDispatcher.createClient()} or {@link NetconfClientDispatcher.createReconnectingClient()} instead.
+ */
+@Deprecated
public class NetconfClient implements Closeable {
private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
private NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
this.label = clientLabelForLogging;
dispatch = netconfClientDispatcher;
- sessionListener = new NetconfClientSessionListener();
+ sessionListener = new SimpleNetconfClientSessionListener();
Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strat);
this.address = address;
clientSession = get(clientFuture);
try {
return clientFuture.get();
} catch (CancellationException e) {
- throw new RuntimeException("Netconf client interrupted", e);
+ throw new RuntimeException("Cancelling " + this, e);
} catch (ExecutionException e) {
- throw new IllegalStateException("Unable to create netconf client", e);
+ throw new IllegalStateException("Unable to create " + this, e);
}
}
- public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- return new NetconfClient(clientLabelForLogging,address,strat,netconfClientDispatcher);
+ public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
+ return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher);
}
- public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher,NetconfClientSessionListener listener) throws InterruptedException {
- return new NetconfClient(clientLabelForLogging,address,strat,netconfClientDispatcher,listener);
+ public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address,
+ ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException {
+ return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher,listener);
}
public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs,
DEFAULT_CONNECT_TIMEOUT), netconfClientDispatcher);
}
- public NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat,
+ public NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy,
NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException{
this.label = clientLabelForLogging;
dispatch = netconfClientDispatcher;
sessionListener = listener;
- Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strat);
+ Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strategy);
this.address = address;
clientSession = get(clientFuture);
this.sessionId = clientSession.getSessionId();
}
- public NetconfMessage sendMessage(NetconfMessage message) {
+ public Future<NetconfMessage> sendRequest(NetconfMessage message) {
+ return ((SimpleNetconfClientSessionListener)sessionListener).sendRequest(message);
+ }
+
+ /**
+ * @deprecated Use {@link sendRequest} instead
+ */
+ @Deprecated
+ public NetconfMessage sendMessage(NetconfMessage message) throws ExecutionException, InterruptedException, TimeoutException {
return sendMessage(message, 5, 1000);
}
- public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) {
- Stopwatch stopwatch = new Stopwatch().start();
- Preconditions.checkState(clientSession.isUp(), "Session was not up yet");
+ /**
+ * @deprecated Use {@link sendRequest} instead
+ */
+ @Deprecated
+ public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) throws ExecutionException, InterruptedException, TimeoutException {
//logger.debug("Sending message: {}",XmlUtil.toString(message.getDocument()));
- clientSession.sendMessage(message);
+ final Stopwatch stopwatch = new Stopwatch().start();
+
try {
- return sessionListener.getLastMessage(attempts, attemptMsDelay);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new RuntimeException(this + " Cannot read message from " + address, e);
- } catch (IllegalStateException e) {
- throw new IllegalStateException(this + " Cannot read message from " + address, e);
+ return sendRequest(message).get(attempts * attemptMsDelay, TimeUnit.MILLISECONDS);
} finally {
stopwatch.stop();
- logger.debug("Total time spent waiting for response {} ms", stopwatch.elapsed(TimeUnit.MILLISECONDS));
+ logger.debug("Total time spent waiting for response from {}: {} ms", address, stopwatch.elapsed(TimeUnit.MILLISECONDS));
}
}
package org.opendaylight.controller.netconf.client;
-import com.google.common.base.Optional;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.HashedWheelTimer;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
-import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+
+import java.io.Closeable;
+import java.net.InetSocketAddress;
+
import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
import org.opendaylight.protocol.framework.AbstractDispatcher;
import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.SessionListener;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
import org.opendaylight.protocol.framework.SessionListenerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.Closeable;
-import java.net.InetSocketAddress;
+import com.google.common.base.Optional;
public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener> implements Closeable {
- private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
+ 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);
}
});
}
- private static class ClientChannelInitializer extends AbstractChannelInitializer {
+ public Future<Void> createReconnectingClient(final InetSocketAddress address,
+ final NetconfClientSessionListener listener,
+ final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) {
+ final ClientChannelInitializer init = new ClientChannelInitializer(negotiatorFactory, listener);
+
+ return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy,
+ new PipelineInitializer<NetconfClientSession>() {
+ @Override
+ public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+ init.initialize(ch, promise);
+ }
+ });
+ }
+
+ private static class ClientChannelInitializer extends AbstractChannelInitializer<NetconfClientSession> {
private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
private final NetconfClientSessionListener sessionListener;
private ClientChannelInitializer(NetconfClientSessionNegotiatorFactory negotiatorFactory,
- NetconfClientSessionListener sessionListener) {
+ NetconfClientSessionListener sessionListener) {
this.negotiatorFactory = negotiatorFactory;
this.sessionListener = sessionListener;
}
@Override
- public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise) {
+ public void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
super.initialize(ch,promise);
}
@Override
- protected void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise) {
- ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() {
- @Override
- public SessionListener<NetconfMessage, NetconfClientSession, NetconfTerminationReason> getSessionListener() {
- return sessionListener;
- }
- }, ch, promise));
+ 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));
}
-
}
+
@Override
public void close() {
try {
package org.opendaylight.controller.netconf.client;
import io.netty.channel.Channel;
-import org.opendaylight.controller.netconf.api.NetconfSession;
-import org.opendaylight.protocol.framework.SessionListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.util.Collection;
-public class NetconfClientSession extends NetconfSession {
+import org.opendaylight.controller.netconf.api.AbstractNetconfSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class NetconfClientSession extends AbstractNetconfSession<NetconfClientSession, NetconfClientSessionListener> {
private static final Logger logger = LoggerFactory.getLogger(NetconfClientSession.class);
private final Collection<String> capabilities;
- public NetconfClientSession(SessionListener sessionListener, Channel channel, long sessionId,
+ public NetconfClientSession(NetconfClientSessionListener sessionListener, Channel channel, long sessionId,
Collection<String> capabilities) {
super(sessionListener,channel,sessionId);
this.capabilities = capabilities;
return capabilities;
}
+ @Override
+ protected NetconfClientSession thisInstance() {
+ return this;
+ }
}
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * 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.client;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
-import org.opendaylight.protocol.framework.SessionListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class NetconfClientSessionListener implements
- SessionListener<NetconfMessage, NetconfClientSession, NetconfTerminationReason> {
-
- private static final Logger logger = LoggerFactory.getLogger(NetconfClientSessionListener.class);
- private AtomicBoolean up = new AtomicBoolean(false);
-
- @Override
- public void onSessionUp(NetconfClientSession clientSession) {
- up.set(true);
- }
-
- @Override
- public void onSessionDown(NetconfClientSession clientSession, Exception e) {
- logger.debug("Client Session {} down, reason: {}", clientSession, e.getMessage());
- up.set(false);
- }
-
- @Override
- public void onSessionTerminated(NetconfClientSession clientSession,
- NetconfTerminationReason netconfTerminationReason) {
- logger.debug("Client Session {} terminated, reason: {}", clientSession,
- netconfTerminationReason.getErrorMessage());
- up.set(false);
- }
-
- @Override
- public synchronized void onMessage(NetconfClientSession session, NetconfMessage message) {
- synchronized (messages) {
- this.messages.add(message);
- }
- }
-
- private int lastReadMessage = -1;
- private List<NetconfMessage> messages = Lists.newArrayList();
-
- public NetconfMessage getLastMessage(int attempts, int attemptMsDelay) throws InterruptedException {
- Preconditions.checkState(up.get(), "Session was not up yet");
-
- for (int i = 0; i < attempts; i++) {
- synchronized (messages) {
- if (messages.size() - 1 > lastReadMessage) {
- lastReadMessage++;
- return messages.get(lastReadMessage);
- }
- }
+import org.opendaylight.controller.netconf.api.NetconfSessionListener;
- if (up.get() == false)
- throw new IllegalStateException("Session ended while trying to read message");
- Thread.sleep(attemptMsDelay);
- }
+public interface NetconfClientSessionListener extends NetconfSessionListener<NetconfClientSession> {
- throw new IllegalStateException("No netconf message to read");
- }
}
package org.opendaylight.controller.netconf.client;
-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;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
+import java.util.Collection;
+import java.util.List;
+
+import javax.annotation.Nullable;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+
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 org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.opendaylight.protocol.framework.SessionListener;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
-import javax.annotation.Nullable;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import java.util.Collection;
-import java.util.List;
+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> {
+ AbstractNetconfSessionNegotiator<NetconfSessionPreferences, NetconfClientSession, NetconfClientSessionListener> {
protected NetconfClientSessionNegotiator(NetconfSessionPreferences sessionPreferences,
- Promise<NetconfClientSession> promise, Channel channel, Timer timer, SessionListener sessionListener,
+ Promise<NetconfClientSession> promise, Channel channel, Timer timer, NetconfClientSessionListener sessionListener,
long connectionTimeoutMillis) {
super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
}
}
@Override
- protected NetconfClientSession getSession(SessionListener 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()));
}
package org.opendaylight.controller.netconf.client;
-import com.google.common.base.Optional;
-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.IOException;
+import java.io.InputStream;
+
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.protocol.framework.SessionListenerFactory;
import org.opendaylight.protocol.framework.SessionNegotiator;
import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
import org.xml.sax.SAXException;
-import java.io.IOException;
-import java.io.InputStream;
-
-public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory {
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
- private final Timer timer;
+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) {
- this.timer = timer;
+ public NetconfClientSessionNegotiatorFactory(Timer timer, Optional<NetconfHelloMessageAdditionalHeader> additionalHeader, long connectionTimeoutMillis) {
+ this.timer = Preconditions.checkNotNull(timer);
this.additionalHeader = additionalHeader;
this.connectionTimeoutMillis = connectionTimeoutMillis;
}
}
@Override
- public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel,
- Promise promise) {
+ public SessionNegotiator<NetconfClientSession> getSessionNegotiator(SessionListenerFactory<NetconfClientSessionListener> sessionListenerFactory, Channel channel,
+ 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);
}
-
}
package org.opendaylight.controller.netconf.client;
-import com.google.common.base.Optional;
-import io.netty.channel.ChannelHandler;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.HashedWheelTimer;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
-import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
import org.opendaylight.controller.netconf.util.handler.ssh.SshHandler;
import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
import org.opendaylight.controller.netconf.util.handler.ssh.client.Invoker;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
-import org.opendaylight.protocol.framework.ProtocolHandlerFactory;
-import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
-import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.SessionListener;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
import org.opendaylight.protocol.framework.SessionListenerFactory;
-import java.io.IOException;
-import java.net.InetSocketAddress;
+import com.google.common.base.Optional;
public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
- private AuthenticationHandler authHandler;
- private HashedWheelTimer timer;
- private NetconfClientSessionNegotiatorFactory negotatorFactory;
+ private final AuthenticationHandler authHandler;
+ private final HashedWheelTimer timer;
+ 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
public Future<NetconfClientSession> createClient(InetSocketAddress address,
final NetconfClientSessionListener sessionListener, ReconnectStrategy strat) {
return super.createClient(address, strat, new PipelineInitializer<NetconfClientSession>() {
@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);
}
});
}
- private static final class NetconfSshClientInitializer extends AbstractChannelInitializer {
+ @Override
+ public Future<Void> createReconnectingClient(final InetSocketAddress address,
+ final NetconfClientSessionListener listener,
+ final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) {
+ final NetconfSshClientInitializer init = new NetconfSshClientInitializer(authHandler, negotiatorFactory, listener);
+
+ return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy,
+ new PipelineInitializer<NetconfClientSession>() {
+ @Override
+ public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+ init.initialize(ch, promise);
+ }
+ });
+ }
+
+ private static final class NetconfSshClientInitializer extends AbstractChannelInitializer<NetconfClientSession> {
- private final NetconfHandlerFactory handlerFactory;
private final AuthenticationHandler authenticationHandler;
private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
private final NetconfClientSessionListener sessionListener;
public NetconfSshClientInitializer(AuthenticationHandler authHandler,
NetconfClientSessionNegotiatorFactory negotiatorFactory,
final NetconfClientSessionListener sessionListener) {
- this.handlerFactory = new NetconfHandlerFactory(new NetconfMessageFactory());
this.authenticationHandler = authHandler;
this.negotiatorFactory = negotiatorFactory;
this.sessionListener = sessionListener;
}
@Override
- public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise) {
+ public void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
try {
Invoker invoker = Invoker.subsystem("netconf");
ch.pipeline().addFirst(new SshHandler(authenticationHandler, invoker));
}
@Override
- protected void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise) {
- ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() {
+ 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 SessionListener<NetconfMessage, NetconfClientSession, NetconfTerminationReason> getSessionListener() {
+ public NetconfClientSessionListener getSessionListener() {
return sessionListener;
}
}, ch, promise));
-
- }
- }
-
- private static final class NetconfHandlerFactory extends ProtocolHandlerFactory<NetconfMessage> {
-
- public NetconfHandlerFactory(final NetconfMessageFactory msgFactory) {
- super(msgFactory);
- }
-
- @Override
- public ChannelHandler[] getEncoders() {
- return new ChannelHandler[] { new ProtocolMessageEncoder(this.msgFactory) };
- }
-
- @Override
- public ChannelHandler[] getDecoders() {
- return new ChannelHandler[] { new ProtocolMessageDecoder(this.msgFactory) };
}
}
}
--- /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.client;
+
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GlobalEventExecutor;
+import io.netty.util.concurrent.Promise;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public class SimpleNetconfClientSessionListener implements NetconfClientSessionListener {
+ private static final class RequestEntry {
+ final Promise<NetconfMessage> promise;
+ final NetconfMessage request;
+
+ public RequestEntry(Promise<NetconfMessage> future, NetconfMessage request) {
+ this.promise = Preconditions.checkNotNull(future);
+ this.request = Preconditions.checkNotNull(request);
+ }
+ }
+
+ private static final Logger logger = LoggerFactory.getLogger(SimpleNetconfClientSessionListener.class);
+
+ @GuardedBy("this")
+ private final Queue<RequestEntry> requests = new ArrayDeque<>();
+
+ @GuardedBy("this")
+ private NetconfClientSession clientSession;
+
+ @GuardedBy("this")
+ private void dispatchRequest() {
+ while (!requests.isEmpty()) {
+ final RequestEntry e = requests.peek();
+ if (e.promise.setUncancellable()) {
+ logger.debug("Sending message {}", e.request);
+ clientSession.sendMessage(e.request);
+ break;
+ }
+
+ logger.debug("Message {} has been cancelled, skipping it", e.request);
+ requests.poll();
+ }
+ }
+
+ @Override
+ public final synchronized void onSessionUp(NetconfClientSession clientSession) {
+ this.clientSession = Preconditions.checkNotNull(clientSession);
+ logger.debug("Client session {} went up", clientSession);
+ dispatchRequest();
+ }
+
+ private synchronized void tearDown(final Exception cause) {
+ final RequestEntry e = requests.poll();
+ if (e != null) {
+ e.promise.setFailure(cause);
+ }
+
+ this.clientSession = null;
+ }
+
+ @Override
+ public final void onSessionDown(NetconfClientSession clientSession, Exception e) {
+ logger.debug("Client Session {} went down unexpectedly", clientSession, e);
+ tearDown(e);
+ }
+
+ @Override
+ public final void onSessionTerminated(NetconfClientSession clientSession,
+ NetconfTerminationReason netconfTerminationReason) {
+ logger.debug("Client Session {} terminated, reason: {}", clientSession,
+ netconfTerminationReason.getErrorMessage());
+ tearDown(new RuntimeException(netconfTerminationReason.getErrorMessage()));
+ }
+
+ @Override
+ public synchronized void onMessage(NetconfClientSession session, NetconfMessage message) {
+ logger.debug("New message arrived: {}", message);
+
+ final RequestEntry e = requests.poll();
+ if (e != null) {
+ e.promise.setSuccess(message);
+ dispatchRequest();
+ } else {
+ logger.info("Ignoring unsolicited message {}", message);
+ }
+ }
+
+ final synchronized Future<NetconfMessage> sendRequest(NetconfMessage message) {
+ final RequestEntry req = new RequestEntry(GlobalEventExecutor.INSTANCE.<NetconfMessage>newPromise(), message);
+
+ requests.add(req);
+ if (clientSession != null) {
+ dispatchRequest();
+ }
+
+ return req.promise;
+ }
+}
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.NetconfUtil;
import org.opendaylight.controller.netconf.util.handler.ssh.authentication.LoginPassword;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.io.IOException;
import java.net.InetSocketAddress;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
@Ignore
public class SSHNetconfClientLiveTest {
+ private static final Logger logger = LoggerFactory.getLogger(SSHNetconfClientLiveTest.class);
NioEventLoopGroup nettyThreadgroup;
NetconfSshClientDispatcher netconfClientDispatcher;
+ InetSocketAddress address;
+ final int connectionAttempts = 10, attemptMsTimeout = 1000;
+ final int connectionTimeoutMillis = 20000;
@Before
public void setUp() {
nettyThreadgroup = new NioEventLoopGroup();
+
netconfClientDispatcher = new NetconfSshClientDispatcher(new LoginPassword(
System.getProperty("username"), System.getProperty("password")),
- nettyThreadgroup, nettyThreadgroup, 5000);
+ nettyThreadgroup, nettyThreadgroup, connectionTimeoutMillis);
+
+ address = new InetSocketAddress(System.getProperty("host"), Integer.parseInt(System.getProperty("port")));
}
+ @Ignore
@Test
public void test() throws Exception {
- InetSocketAddress address = new InetSocketAddress(System.getProperty("host"), 830);
- int connectionAttempts = 10, attemptMsTimeout = 1000;
+ //runnable.run();
+ }
- NetconfClient netconfClient = new NetconfClient("client", address, connectionAttempts,
- attemptMsTimeout, netconfClientDispatcher);
+ @Test
+ public void testInExecutor() throws Exception {
+ int threads = 4;
+ ExecutorService executorService = Executors.newFixedThreadPool(threads);
+ try {
+ for (int i= 0;i< threads;i++) {
+ InetSocketAddress address = new InetSocketAddress(System.getProperty("host"),
+ Integer.parseInt(System.getProperty("port")));
+ NetconfRunnable runnable = new NetconfRunnable(address);
+ executorService.execute(runnable);
+ }
+ executorService.shutdown();
+ executorService.awaitTermination(1, TimeUnit.MINUTES);
- netconfClient.getCapabilities();
- NetconfMessage netconfMessage = NetconfUtil.createMessage(getClass().getResourceAsStream("/get_schema.xml"));
- NetconfMessage response = netconfClient.sendMessage(netconfMessage);
- NetconfUtil.checkIsMessageOk(response);
+ } finally {
+ executorService.shutdownNow();
+ }
}
+
+ class NetconfRunnable implements Runnable {
+ private final InetSocketAddress address;
+
+ NetconfRunnable(InetSocketAddress address) {
+ this.address = address;
+ }
+
+ @Override
+ public void run() {
+ try (NetconfClient netconfClient = new NetconfClient(address.toString(), address, connectionAttempts,
+ attemptMsTimeout, netconfClientDispatcher);) {
+ logger.info("OK {}", address);
+ } catch (InterruptedException | IOException e) {
+ logger.error("Failed {}", address, e);
+ }
+ }
+ };
}
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.api.NetconfSession;
+
+import java.net.InetSocketAddress;
+
import org.opendaylight.controller.netconf.impl.util.DeserializerExceptionHandler;
import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
import org.opendaylight.protocol.framework.AbstractDispatcher;
-import java.net.InetSocketAddress;
-
-public class NetconfServerDispatcher extends AbstractDispatcher<NetconfSession, NetconfServerSessionListener> {
+public class NetconfServerDispatcher extends AbstractDispatcher<NetconfServerSession, NetconfServerSessionListener> {
private final ServerChannelInitializer initializer;
public ChannelFuture createServer(InetSocketAddress address) {
- return super.createServer(address, new PipelineInitializer<NetconfSession>() {
+ return super.createServer(address, new PipelineInitializer<NetconfServerSession>() {
@Override
- public void initializeChannel(final SocketChannel ch, final Promise<NetconfSession> promise) {
+ public void initializeChannel(final SocketChannel ch, final Promise<NetconfServerSession> promise) {
initializer.initialize(ch, promise);
}
});
}
- public static class ServerChannelInitializer extends AbstractChannelInitializer {
+ 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<? extends NetconfSession> 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 java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.opendaylight.controller.netconf.api.NetconfSession;
+import org.opendaylight.controller.netconf.api.AbstractNetconfSession;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
-import org.opendaylight.protocol.framework.SessionListener;
+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;
import com.google.common.base.Preconditions;
-public class NetconfServerSession extends NetconfSession implements NetconfManagementSession {
+public final class NetconfServerSession extends AbstractNetconfSession<NetconfServerSession, NetconfServerSessionListener> implements NetconfManagementSession {
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(SessionListener sessionListener, Channel channel, long sessionId,
- NetconfServerSessionNegotiator.AdditionalHeader header) {
+ public NetconfServerSession(NetconfServerSessionListener sessionListener, Channel channel, long sessionId,
+ 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();
private Class<? extends Transport> getTransportForString(String transport) {
switch(transport) {
- case "ssh" : return NetconfSsh.class;
- case "tcp" : return NetconfTcp.class;
- default: throw new IllegalArgumentException("Unknown transport type " + transport);
+ case "ssh" : return NetconfSsh.class;
+ case "tcp" : return NetconfTcp.class;
+ default: throw new IllegalArgumentException("Unknown transport type " + transport);
}
}
return dateFormat.format(loginTime);
}
+ @Override
+ protected NetconfServerSession thisInstance() {
+ return this;
+ }
}
package org.opendaylight.controller.netconf.impl;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
+import static com.google.common.base.Preconditions.checkState;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfSessionListener;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
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.SessionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
-import static com.google.common.base.Preconditions.checkState;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
-public class NetconfServerSessionListener implements
- SessionListener<NetconfMessage, NetconfServerSession, NetconfTerminationReason> {
+public class NetconfServerSessionListener implements NetconfSessionListener<NetconfServerSession> {
+ public static final String MESSAGE_ID = "message-id";
static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionListener.class);
- public static final String MESSAGE_ID = "message-id";
private final SessionMonitoringService monitoringService;
+ private final NetconfOperationRouterImpl operationRouter;
- private NetconfOperationRouterImpl operationRouter;
-
- public NetconfServerSessionListener(NetconfOperationRouterImpl operationRouter,
- SessionMonitoringService monitoringService) {
+ public NetconfServerSessionListener(NetconfOperationRouterImpl operationRouter, SessionMonitoringService monitoringService) {
this.operationRouter = operationRouter;
this.monitoringService = monitoringService;
}
package org.opendaylight.controller.netconf.impl;
-import com.google.common.base.Optional;
-import io.netty.channel.Channel;
-import io.netty.util.Timer;
-import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
+import java.net.InetSocketAddress;
+
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.protocol.framework.SessionListener;
+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 java.net.InetSocketAddress;
+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> {
+ AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession, NetconfServerSessionListener> {
static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiator.class);
protected NetconfServerSessionNegotiator(NetconfServerSessionPreferences sessionPreferences,
- Promise<NetconfServerSession> promise, Channel channel, Timer timer, SessionListener sessionListener,
+ Promise<NetconfServerSession> promise, Channel channel, Timer timer, NetconfServerSessionListener sessionListener,
long connectionTimeoutMillis) {
super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
}
@Override
- protected NetconfServerSession getSession(SessionListener 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();
- }
- }
-
-}
+ }
import io.netty.channel.Channel;
import io.netty.util.Timer;
import io.netty.util.concurrent.Promise;
-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 javax.xml.xpath.XPathExpression;
import java.io.InputStream;
-public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory {
+public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfHelloMessage, NetconfServerSession, NetconfServerSessionListener> {
public static final String SERVER_HELLO_XML_LOCATION = "/server_hello.xml";
}
@Override
- public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel,
- Promise promise) {
+ public SessionNegotiator<NetconfServerSession> getSessionNegotiator(SessionListenerFactory<NetconfServerSessionListener> sessionListenerFactory, Channel channel,
+ Promise<NetconfServerSession> promise) {
long sessionId = idProvider.getNextSessionId();
NetconfServerSessionPreferences proposal = new NetconfServerSessionPreferences(createHelloMessage(sessionId),
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() {
- return (Document) this.helloMessageTemplate.cloneNode(true);
+ return (Document) helloMessageTemplate.cloneNode(true);
}
}
package org.opendaylight.controller.netconf.impl.mapping.operations;
-import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
-import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-public class DefaultCloseSession extends AbstractNetconfOperation implements DefaultNetconfOperation {
+public class DefaultCloseSession extends AbstractNetconfOperation {
public static final String CLOSE_SESSION = "close-session";
- private NetconfSession netconfSession;
public DefaultCloseSession(String netconfSessionIdForReporting) {
super(netconfSessionIdForReporting);
opRouter.close();
return document.createElement(XmlNetconfConstants.OK);
}
-
- @Override
- public void setNetconfSession(NetconfSession s) {
- this.netconfSession = s;
- }
-
- public NetconfSession getNetconfSession() {
- return netconfSession;
- }
}
import java.util.HashMap;
import java.util.Map;
-import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
-import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import com.google.common.base.Optional;
import com.google.common.collect.Maps;
-public final class DefaultGetSchema extends AbstractNetconfOperation implements DefaultNetconfOperation {
-
- private final CapabilityProvider cap;
- private NetconfSession netconfSession;
+public final class DefaultGetSchema extends AbstractNetconfOperation {
+ public static final String GET_SCHEMA = "get-schema";
+ public static final String IDENTIFIER = "identifier";
+ public static final String VERSION = "version";
private static final Logger logger = LoggerFactory.getLogger(DefaultGetSchema.class);
+ private final CapabilityProvider cap;
public DefaultGetSchema(CapabilityProvider cap, String netconfSessionIdForReporting) {
super(netconfSessionIdForReporting);
this.cap = cap;
}
- public static final String GET_SCHEMA = "get-schema";
- public static final String IDENTIFIER = "identifier";
- public static final String VERSION = "version";
-
@Override
protected HandlingPriority canHandle(String netconfOperationName, String namespace) {
if (netconfOperationName.equals("get-schema") == false)
} else {
version = Optional.absent();
}
-
}
}
-
- public void setNetconfSession(NetconfSession s) {
- this.netconfSession = s;
- }
-
- public NetconfSession getNetconfSession() {
- return netconfSession;
- }
}
*/
package org.opendaylight.controller.netconf.impl.osgi;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.opendaylight.controller.netconf.api.NetconfSession;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
+import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
public class NetconfOperationRouterImpl implements NetconfOperationRouter {
public NetconfOperationRouterImpl(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot,
CapabilityProvider capabilityProvider, DefaultCommitNotificationProducer commitNotifier) {
- this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot;
+ this.netconfOperationServiceSnapshot = Preconditions.checkNotNull(netconfOperationServiceSnapshot);
+ this.capabilityProvider = Preconditions.checkNotNull(capabilityProvider);
- this.capabilityProvider = capabilityProvider;
-
- Set<NetconfOperation> defaultNetconfOperations = Sets.newHashSet();
- defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, netconfOperationServiceSnapshot
- .getNetconfSessionIdForReporting()));
- defaultNetconfOperations.add(new DefaultCloseSession(netconfOperationServiceSnapshot
- .getNetconfSessionIdForReporting()));
- defaultNetconfOperations.add(new DefaultStartExi(netconfOperationServiceSnapshot
- .getNetconfSessionIdForReporting()));
- defaultNetconfOperations.add(new DefaultStopExi(netconfOperationServiceSnapshot
- .getNetconfSessionIdForReporting()));
+ final String sessionId = netconfOperationServiceSnapshot.getNetconfSessionIdForReporting();
+ final Set<NetconfOperation> defaultNetconfOperations = Sets.newHashSet();
+ defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, sessionId));
+ defaultNetconfOperations.add(new DefaultCloseSession(sessionId));
+ defaultNetconfOperations.add(new DefaultStartExi(sessionId));
+ defaultNetconfOperations.add(new DefaultStopExi(sessionId));
allNetconfOperations = getAllNetconfOperations(defaultNetconfOperations, netconfOperationServiceSnapshot);
- DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider,
- netconfOperationServiceSnapshot.getNetconfSessionIdForReporting());
+ DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider, sessionId);
Set<NetconfOperationFilter> defaultFilters = Sets.<NetconfOperationFilter> newHashSet(defaultCommit);
allSortedFilters = getAllNetconfFilters(defaultFilters, netconfOperationServiceSnapshot);
}
private class NetconfOperationExecution implements NetconfOperationFilterChain {
private final NetconfOperation operationWithHighestPriority;
- private NetconfOperationExecution(NetconfOperation operationWithHighestPriority) {
- this.operationWithHighestPriority = operationWithHighestPriority;
- }
-
public NetconfOperationExecution(TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority,
HandlingPriority highestFoundPriority) {
operationWithHighestPriority = sortedPriority.get(highestFoundPriority).iterator().next();
+++ /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());
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-
-import java.util.Queue;
-
import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
+import java.util.Queue;
+
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
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.messages.NetconfMessageConstants;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
-import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
public class MessageParserTest {
private NetconfMessage msg;
- private NetconfMessageFactory msgFactory = new NetconfMessageFactory();
@Before
public void setUp() throws Exception {
public void testChunkedFramingMechanismOnPipeline() throws Exception {
EmbeddedChannel testChunkChannel = new EmbeddedChannel(
FramingMechanismHandlerFactory.createHandler(FramingMechanism.CHUNK),
- new ProtocolMessageEncoder<NetconfMessage>(msgFactory),
+ new NetconfMessageToXMLEncoder(),
new NetconfMessageAggregator(FramingMechanism.CHUNK), new NetconfMessageChunkDecoder(),
- new ProtocolMessageDecoder<NetconfMessage>(msgFactory));
+ new NetconfXMLToMessageDecoder());
testChunkChannel.writeOutbound(this.msg);
Queue<Object> messages = testChunkChannel.outboundMessages();
assertFalse(messages.isEmpty());
- int msgLength = this.msgFactory.put(this.msg).length;
+ final NetconfMessageToXMLEncoder enc = new NetconfMessageToXMLEncoder();
+ final ByteBuf out = Unpooled.buffer();
+ enc.encode(null, msg, out);
+ int msgLength = out.readableBytes();
+
int chunkCount = msgLength / NetconfMessageConstants.MAX_CHUNK_SIZE;
if ((msgLength % NetconfMessageConstants.MAX_CHUNK_SIZE) != 0) {
chunkCount++;
public void testEOMFramingMechanismOnPipeline() throws Exception {
EmbeddedChannel testChunkChannel = new EmbeddedChannel(
FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM),
- new ProtocolMessageEncoder<NetconfMessage>(msgFactory), new NetconfMessageAggregator(
- FramingMechanism.EOM), new ProtocolMessageDecoder<NetconfMessage>(msgFactory));
+ new NetconfMessageToXMLEncoder(), new NetconfMessageAggregator(
+ FramingMechanism.EOM), new NetconfXMLToMessageDecoder());
testChunkChannel.writeOutbound(this.msg);
ByteBuf recievedOutbound = (ByteBuf) testChunkChannel.readOutbound();
package org.opendaylight.controller.netconf.it;
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import static java.util.Collections.emptyList;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import io.netty.channel.ChannelFuture;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import javax.management.ObjectName;
+import javax.xml.parsers.ParserConfigurationException;
+
import junit.framework.Assert;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
-import static java.util.Collections.emptyList;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
public class NetconfITTest extends AbstractNetconfConfigTest {
private static final String PASSWORD = "netconf";
private NetconfMessage getConfig, getConfigCandidate, editConfig,
- closeSession, startExi, stopExi;
+ closeSession, startExi, stopExi;
private DefaultCommitNotificationProducer commitNot;
private NetconfServerDispatcher dispatch;
}
}
- */
+ */
@Test
public void testCloseSession() throws Exception {
assertEquals("ok", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName());
}
- private Document assertGetConfigWorks(final NetconfClient netconfClient) throws InterruptedException {
+ private Document assertGetConfigWorks(final NetconfClient netconfClient) throws InterruptedException, ExecutionException, TimeoutException {
return assertGetConfigWorks(netconfClient, this.getConfig);
}
private Document assertGetConfigWorks(final NetconfClient netconfClient, final NetconfMessage getConfigMessage)
- throws InterruptedException {
+ throws InterruptedException, ExecutionException, TimeoutException {
final NetconfMessage rpcReply = netconfClient.sendMessage(getConfigMessage);
assertNotNull(rpcReply);
assertEquals("data", XmlElement.fromDomDocument(rpcReply.getDocument()).getOnlyChildElement().getName());
sess.getStdin().write(XmlUtil.toString(this.getConfig.getDocument()).getBytes());
new Thread(){
- public void run(){
- while (true){
- byte[] bytes = new byte[1024];
- int c = 0;
- try {
- c = sess.getStdout().read(bytes);
- } catch (IOException e) {
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
- }
- logger.info("got data:"+bytes);
- if (c == 0) break;
- }
- }
+ @Override
+ public void run(){
+ while (true){
+ byte[] bytes = new byte[1024];
+ int c = 0;
+ try {
+ c = sess.getStdout().read(bytes);
+ } catch (IOException e) {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ logger.info("got data:"+bytes);
+ if (c == 0) break;
+ }
+ }
}.join();
}
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;
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;
}
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;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.concurrent.Promise;
+
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
-import org.opendaylight.controller.netconf.util.handler.NetconfHandlerFactory;
+import org.opendaylight.controller.netconf.util.handler.NetconfHelloMessageToXMLEncoder;
import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
+import org.opendaylight.controller.netconf.util.handler.NetconfXMLToHelloMessageDecoder;
import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
-public abstract class AbstractChannelInitializer {
+public abstract class AbstractChannelInitializer<S extends NetconfSession> {
+
+ 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());
+ }
- public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise){
- NetconfHandlerFactory handlerFactory = new NetconfHandlerFactory(new NetconfMessageFactory());
- ch.pipeline().addLast("aggregator", new NetconfMessageAggregator(FramingMechanism.EOM));
- ch.pipeline().addLast(handlerFactory.getDecoders());
- initializeAfterDecoder(ch, promise);
- ch.pipeline().addLast("frameEncoder", FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
- ch.pipeline().addLast(handlerFactory.getEncoders());
+ 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<? extends NetconfSession> 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 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;
+import java.util.concurrent.TimeUnit;
+
+import org.opendaylight.controller.netconf.api.AbstractNetconfSession;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
+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.opendaylight.protocol.framework.SessionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
-import java.util.concurrent.TimeUnit;
+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 NetconfSession>
- extends AbstractSessionNegotiator<NetconfMessage, S> {
+public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionPreferences, S extends AbstractNetconfSession<S, L>, L extends NetconfSessionListener<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;
- private final SessionListener sessionListener;
+ private final L sessionListener;
private Timeout timeout;
/**
private final long connectionTimeoutMillis;
protected AbstractNetconfSessionNegotiator(P sessionPreferences, Promise<S> promise, Channel channel, Timer timer,
- SessionListener sessionListener, long connectionTimeoutMillis) {
+ L sessionListener, long connectionTimeoutMillis) {
super(promise, channel);
this.sessionPreferences = sessionPreferences;
this.timer = timer;
public void run(final Timeout timeout) throws Exception {
synchronized (this) {
if (state != State.ESTABLISHED) {
- logger.debug("Connection timeout after {}", timeout);
+ logger.debug("Connection timeout after {}, session is in state {}", timeout, state);
final IllegalStateException cause = new IllegalStateException(
"Session was not established after " + timeout);
negotiationFailed(cause);
}
@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(SessionListener 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 isHelloMessage(Document doc) {
- try {
- XmlElement.fromDomElementWithExpected(doc.getDocumentElement(), "hello",
- XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+ private boolean shouldUseChunkFraming(Document doc) {
+ return containsBase11Capability(doc)
+ && containsBase11Capability(sessionPreferences.getHelloMessage().getDocument());
+ }
- } catch (IllegalArgumentException | IllegalStateException e) {
- return false;
- }
- return true;
+ /**
+ * 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());
}
- private void changeState(final State newState) {
+ 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,
newState);
if (state == State.OPEN_WAIT && newState == State.FAILED)
return true;
+ logger.debug("Transition from {} to {} is not allowed", state, newState);
return false;
}
}
+++ /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.handler;
-
-import io.netty.channel.ChannelHandler;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
-import org.opendaylight.protocol.framework.ProtocolHandlerFactory;
-import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
-import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
-
-public class NetconfHandlerFactory extends ProtocolHandlerFactory<NetconfMessage> {
-
- public NetconfHandlerFactory(final NetconfMessageFactory msgFactory) {
- super(msgFactory);
- }
-
- @Override
- public ChannelHandler[] getEncoders() {
- return new ChannelHandler[] { new ProtocolMessageEncoder(this.msgFactory) };
- }
-
- @Override
- public ChannelHandler[] getDecoders() {
- return new ChannelHandler[] { new ProtocolMessageDecoder(this.msgFactory) };
- }
-
-}
--- /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);
+ }
+}
package org.opendaylight.controller.netconf.util.handler;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
import java.nio.charset.Charset;
import java.util.List;
+import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
-import org.opendaylight.protocol.framework.DeserializerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.ByteToMessageDecoder;
-
public class NetconfMessageChunkDecoder extends ByteToMessageDecoder {
private final static Logger logger = LoggerFactory.getLogger(NetconfMessageChunkDecoder.class);
in.readBytes(byteBufMsg, chunkSize);
isParsed = false;
} else {
- throw new DeserializerException("Unable to parse chunked data or header.");
+ throw new NetconfDeserializerException("Unable to parse chunked data or header.");
}
} catch (Exception e) {
logger.error("Failed to decode chunked message.", e);
--- /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 io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToByteEncoder;
+
+import java.nio.ByteBuffer;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+
+public class NetconfMessageToXMLEncoder extends MessageToByteEncoder<NetconfMessage> {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfMessageToXMLEncoder.class);
+
+ private final Optional<String> clientId;
+
+ public NetconfMessageToXMLEncoder() {
+ this(Optional.<String>absent());
+ }
+
+ public NetconfMessageToXMLEncoder(Optional<String> clientId) {
+ this.clientId = clientId;
+ }
+
+ @Override
+ @VisibleForTesting
+ public void encode(ChannelHandlerContext ctx, NetconfMessage msg, ByteBuf out) throws Exception {
+ LOG.debug("Sent to encode : {}", msg);
+
+ if (clientId.isPresent()) {
+ Comment comment = msg.getDocument().createComment("clientId:" + clientId.get());
+ msg.getDocument().appendChild(comment);
+ }
+
+ final ByteBuffer msgBytes = encodeMessage(msg);
+
+ LOG.trace("Putting message \n{}", xmlToString(msg.getDocument()));
+ out.writeBytes(msgBytes);
+ }
+
+ 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();
+ }
+
+}
--- /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.io.ByteArrayInputStream;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Charsets;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
+public class NetconfXMLToMessageDecoder extends ByteToMessageDecoder {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToMessageDecoder.class);
+
+ @Override
+ @VisibleForTesting
+ public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
+ if (in.readableBytes() == 0) {
+ LOG.debug("No more content in incoming buffer.");
+ return;
+ }
+
+ in.markReaderIndex();
+ try {
+ LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in));
+ byte[] bytes = new byte[in.readableBytes()];
+ in.readBytes(bytes);
+
+ logMessage(bytes);
+
+ bytes = preprocessMessageBytes(bytes);
+ NetconfMessage message;
+ try {
+ Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes));
+ 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();
+ }
+ }
+
+ protected void cleanUpAfterDecode() {}
+
+ protected NetconfMessage buildNetconfMessage(Document doc) {
+ return new NetconfMessage(doc);
+ }
+
+ protected byte[] preprocessMessageBytes(byte[] bytes) {
+ return bytes;
+ }
+
+ private void logMessage(byte[] bytes) {
+ String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
+ LOG.debug("Parsing message \n{}", s);
+ }
+
+}
* Exception class which provides notification about exceptional situations at the virtual socket layer.
*/
public class VirtualSocketException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
}
package org.opendaylight.controller.netconf.util.mapping;
+import java.util.Map;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
-import java.util.Map;
-
public abstract class AbstractNetconfOperation implements NetconfOperation {
private final String netconfSessionIdForReporting;
this.netconfSessionIdForReporting = netconfSessionIdForReporting;
}
- public String getNetconfSessionIdForReporting() {
+ public final String getNetconfSessionIdForReporting() {
return netconfSessionIdForReporting;
}
protected abstract HandlingPriority canHandle(String operationName, String netconfOperationNamespace);
@Override
- public Document handle(Document message, NetconfOperationRouter opRouter) throws NetconfDocumentedException {
+ public final Document handle(Document message, NetconfOperationRouter opRouter) throws NetconfDocumentedException {
XmlElement requestElement = getRequestElementWithCheck(message);
--- /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();
- }
-}
+++ /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 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.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.opendaylight.protocol.framework.DeserializerException;
-import org.opendaylight.protocol.framework.DocumentedException;
-import org.opendaylight.protocol.framework.ProtocolMessageFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Comment;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableList;
-
-/**
- * NetconfMessageFactory for (de)serializing DOM documents.
- */
-public final class NetconfMessageFactory implements ProtocolMessageFactory<NetconfMessage> {
-
- private static final Logger logger = LoggerFactory.getLogger(NetconfMessageFactory.class);
- private static final List<byte[]> POSSIBLE_STARTS = ImmutableList.of(
- "[".getBytes(Charsets.UTF_8), "\r\n[".getBytes(Charsets.UTF_8), "\n[".getBytes(Charsets.UTF_8));
- private static final List<byte[]> POSSIBLE_ENDS = ImmutableList.of(
- "]\n".getBytes(Charsets.UTF_8), "]\r\n".getBytes(Charsets.UTF_8));
-
- private final Optional<String> clientId;
-
- public NetconfMessageFactory() {
- clientId = Optional.absent();
- }
-
- public NetconfMessageFactory(Optional<String> clientId) {
- this.clientId = clientId;
- }
-
- @Override
- public NetconfMessage parse(byte[] bytes) throws DeserializerException, DocumentedException {
- logMessage(bytes);
-
- String additionalHeader = null;
-
- 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);
- }
- }
- NetconfMessage message;
- try {
- Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes));
- message = new NetconfMessage(doc, additionalHeader);
- } catch (final SAXException | IOException | IllegalStateException e) {
- throw new NetconfDeserializerException("Could not parse message from " + new String(bytes), e);
- }
- return message;
- }
-
- 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 int getAdditionalHeaderEndIndex(byte[] bytes) {
- for (byte[] possibleEnd : POSSIBLE_ENDS) {
- int idx = findByteSequence(bytes, possibleEnd);
-
- if (idx != -1) {
- return idx;
- }
- }
-
- return -1;
- }
-
- 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();
- logger.debug("Parsing message \n{}", s);
- }
-
- private String additionalHeaderToString(byte[] bytes) {
- return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
- }
-
- @Override
- public byte[] put(NetconfMessage netconfMessage) {
- if (clientId.isPresent()) {
- Comment comment = netconfMessage.getDocument().createComment("clientId:" + clientId.get());
- netconfMessage.getDocument().appendChild(comment);
- }
- ByteBuffer msgBytes;
- if(netconfMessage.getAdditionalHeader().isPresent()) {
- String header = netconfMessage.getAdditionalHeader().get();
- logger.trace("Header of netconf message parsed \n{}", header);
- msgBytes = Charsets.UTF_8.encode(header + xmlToString(netconfMessage.getDocument()));
- } else {
- msgBytes = Charsets.UTF_8.encode(xmlToString(netconfMessage.getDocument()));
- }
- String content = xmlToString(netconfMessage.getDocument());
-
- logger.trace("Putting message \n{}", content);
- byte[] b = new byte[msgBytes.limit()];
- msgBytes.get(b);
- return b;
- }
-
- private String xmlToString(Document doc) {
- return XmlUtil.toString(doc, false);
- }
-}
*/
package org.opendaylight.controller.netconf.util.messages;
-import com.google.common.io.Files;
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import io.netty.buffer.Unpooled;
import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
-public class NetconfMessageFactoryTest {
+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 {
- NetconfMessageFactory parser = new NetconfMessageFactory();
+ NetconfXMLToMessageDecoder parser = new NetconfXMLToHelloMessageDecoder();
File authHelloFile = new File(getClass().getResource("/netconfMessages/client_hello_with_auth.xml").getFile());
- parser.parse(Files.toByteArray(authHelloFile));
+ final List<Object> out = new ArrayList<>();
+ parser.decode(null, Unpooled.wrappedBuffer(Files.toByteArray(authHelloFile)), out);
+ assertEquals(1, out.size());
}
}
<url>${sitedeploy}</url>
</site>
</distributionManagement>
- <groupId>org.opendaylight.controller</groupId>
<artifactId>networkconfig.neutron.implementation</artifactId>
<version>0.4.2-SNAPSHOT</version>
<packaging>bundle</packaging>
<url>${sitedeploy}</url>
</site>
</distributionManagement>
- <groupId>org.opendaylight.controller</groupId>
<artifactId>networkconfig.neutron</artifactId>
<version>0.4.2-SNAPSHOT</version>
<packaging>bundle</packaging>
}
gatewayIPAssigned = false;
dnsNameservers = new ArrayList<String>();
- allocationPools = new ArrayList<NeutronSubnet_IPAllocationPool>();
- hostRoutes = new ArrayList<NeutronSubnet_HostRoute>();
- try {
- SubnetUtils util = new SubnetUtils(cidr);
- SubnetInfo info = util.getInfo();
- if (gatewayIP == null) {
- gatewayIP = info.getLowAddress();
- }
- if (allocationPools.size() < 1) {
- NeutronSubnet_IPAllocationPool source =
- new NeutronSubnet_IPAllocationPool(info.getLowAddress(),
- info.getHighAddress());
- allocationPools = source.splitPool(gatewayIP);
+ if (hostRoutes == null) {
+ hostRoutes = new ArrayList<NeutronSubnet_HostRoute>();
+ }
+ if (allocationPools == null) {
+ allocationPools = new ArrayList<NeutronSubnet_IPAllocationPool>();
+ try {
+ SubnetUtils util = new SubnetUtils(cidr);
+ SubnetInfo info = util.getInfo();
+ if (gatewayIP == null) {
+ gatewayIP = info.getLowAddress();
+ }
+ if (allocationPools.size() < 1) {
+ NeutronSubnet_IPAllocationPool source =
+ new NeutronSubnet_IPAllocationPool(info.getLowAddress(),
+ info.getHighAddress());
+ allocationPools = source.splitPool(gatewayIP);
+ }
+ } catch (Exception e) {
+ return false;
}
- } catch (Exception e) {
- return false;
}
return true;
}
<tag>HEAD</tag>
</scm>
- <groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager.northbound</artifactId>
<version>0.4.2-SNAPSHOT</version>
<packaging>bundle</packaging>
<tag>HEAD</tag>
</scm>
- <groupId>org.opendaylight.controller</groupId>
<artifactId>northbound.integrationtest</artifactId>
<version>0.4.2-SNAPSHOT</version>
<pluginRepositories>
<url>${sitedeploy}</url>
</site>
</distributionManagement>
- <groupId>org.opendaylight.controller</groupId>
<artifactId>networkconfig.neutron.northbound</artifactId>
<version>0.4.2-SNAPSHOT</version>
<packaging>bundle</packaging>
@Path("/ports")
public class NeutronPortsNorthbound {
+ final String mac_regex="^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$";
+
private NeutronPort extractFields(NeutronPort o, List<String> fields) {
return o.extractFields(fields);
}
return Response.status(404).build();
}
if (singleton.getMacAddress() == null ||
- !singleton.getMacAddress().matches("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$")) {
+ !singleton.getMacAddress().matches(mac_regex)) {
return Response.status(400).build();
}
if (portInterface.macInUse(singleton.getMacAddress())) {
if (!networkInterface.networkExists(test.getNetworkUUID())) {
return Response.status(404).build();
}
- if (!test.getMacAddress().matches("^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$")) {
+ if (!test.getMacAddress().matches(mac_regex)) {
return Response.status(400).build();
}
if (portInterface.macInUse(test.getMacAddress())) {
* {@link org.opendaylight.controller.sal.core.Property} attached to
* it.
*
- * <pre>
+ * <pre>
*
* Example:
*
* Type of the node connector being programmed (Eg. 'OF')
* @param nodeConnectorId
* NodeConnector Identifier as specified by
- * {@link org.opendaylight.controller.sal.core.NodeConnector}
- * (Eg. '2')
+ * {@link org.opendaylight.controller.sal.core.NodeConnector}.
+ * (Eg. '2'). If nodeConnecterId contains forward slash(/),
+ * replace forward slash with underscore(_) in the URL. (Eg. for
+ * Ethernet1/2, use Ethernet1_2)
* @param propertyName
* Name of the Property specified by
* {@link org.opendaylight.controller.sal.core.Property} and its
* extended classes
* @return Response as dictated by the HTTP Response Status code
*
- * <pre>
+ * <pre>
*
* Example:
*
handleNodeAvailability(containerName, nodeType, nodeId);
Node node = Node.fromString(nodeType, nodeId);
+ if (nodeConnectorId.contains("_")) {
+ nodeConnectorId = nodeConnectorId.replace("_", "/");
+ }
+
handleNodeConnectorAvailability(containerName, node, nodeConnectorType, nodeConnectorId);
NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
* @param nodeConnectorId
* NodeConnector Identifier as specified by
* {@link org.opendaylight.controller.sal.core.NodeConnector}
- * (Eg. '1')
+ * (Eg. '1'). If nodeConnecterId contains forward slash(/),
+ * replace forward slash with underscore(_) in the URL. (Eg. for
+ * Ethernet1/2, use Ethernet1_2)
* @param propertyName
* Name of the Property specified by
* {@link org.opendaylight.controller.sal.core.Property} and its
* extended classes. Property that can be deleted is bandwidth
* @return Response as dictated by the HTTP Response Status code
*
- * <pre>
+ * <pre>
*
* Example:
*
handleNodeAvailability(containerName, nodeType, nodeId);
Node node = Node.fromString(nodeType, nodeId);
+ if (nodeConnectorId.contains("_")) {
+ nodeConnectorId = nodeConnectorId.replace("_", "/");
+ }
+
handleNodeConnectorAvailability(containerName, node, nodeConnectorType, nodeConnectorId);
NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
Status ret = switchManager.removeNodeConnectorProp(nc, propertyName);
.getLogger(Controller.class);
private ControllerIO controllerIO;
private Thread switchEventThread;
+ private volatile boolean shutdownSwitchEventThread;// default to false
private ConcurrentHashMap<Long, ISwitch> switches;
private PriorityBlockingQueue<SwitchEvent> switchEvents;
// only 1 message listener per OFType
while (true) {
try {
+ if(shutdownSwitchEventThread) {
+ // break out of the infinite loop
+ // if you are shutting down
+ logger.info("Switch Event Thread is shutting down");
+ break;
+ }
SwitchEvent ev = switchEvents.take();
SwitchEvent.SwitchEventType eType = ev.getEventType();
ISwitch sw = ev.getSwitch();
logger.error("Unknown switch event {}", eType.ordinal());
}
} catch (InterruptedException e) {
- switchEvents.clear();
- return;
+ // nothing to do except retry
+ } catch (Exception e) {
+ // log the exception and retry
+ logger.warn("Exception in Switch Event Thread is {}" ,e);
}
}
+ switchEvents.clear();
}
-
}
/**
((SwitchHandler) entry.getValue()).stop();
it.remove();
}
+ shutdownSwitchEventThread = true;
switchEventThread.interrupt();
try {
controllerIO.shutDown();
this.myAppData = ByteBuffer
.allocate(session.getApplicationBufferSize());
this.peerAppData = ByteBuffer.allocate(session
- .getApplicationBufferSize() * 2);
+ .getApplicationBufferSize() * 20);
this.myNetData = ByteBuffer.allocate(session.getPacketBufferSize());
- this.peerNetData = ByteBuffer.allocate(session.getPacketBufferSize() * 2);
+ this.peerNetData = ByteBuffer.allocate(session.getPacketBufferSize() * 20);
}
@Override
updateProdEdge(edge, props);
} catch (Exception e) {
- logger.warn("Caught exception ", e);
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "Caught exception while attempting to snoop non controller generated or malformed LLDP frame sent by {} and received on {}: {}",
+ HexEncode.bytesToHexStringFormat(ethPkt.getSourceMACAddress()), dstNodeConnector,
+ e.getMessage());
+ }
}
}
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2013-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,
* @return the int variable containing the unsigned byte value
*/
public static int getUnsignedByte(byte b) {
- return (b > 0) ? (int) b : (b & 0x7F | 0x80);
+ return b & 0xFF;
}
/**
* @return the int variable containing the unsigned short value
*/
public static int getUnsignedShort(short s) {
- return (s > 0) ? (int) s : (s & 0x7FFF | 0x8000);
+ return s & 0xFFFF;
}
/**
public static byte[] getBroadcastMACAddr() {
return Arrays.copyOf(BroadcastMACAddr, BroadcastMACAddr.length);
}
-
}
-
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2013-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,
Assert.assertTrue(NetUtils
.isIPAddressValid("2001:420:281:1004:407a:57f4:4d15:c355"));
}
+
+ @Test
+ public void testGetUnsignedByte() {
+ Assert.assertEquals(0, NetUtils.getUnsignedByte((byte) 0x00));
+ Assert.assertEquals(1, NetUtils.getUnsignedByte((byte) 0x01));
+ Assert.assertEquals(127, NetUtils.getUnsignedByte((byte) 0x7f));
+
+ Assert.assertEquals(128, NetUtils.getUnsignedByte((byte) 0x80));
+ Assert.assertEquals(255, NetUtils.getUnsignedByte((byte) 0xff));
+ }
+
+ @Test
+ public void testGetUnsignedShort() {
+ Assert.assertEquals(0, NetUtils.getUnsignedShort((short) 0x0000));
+ Assert.assertEquals(1, NetUtils.getUnsignedShort((short) 0x0001));
+ Assert.assertEquals(32767, NetUtils.getUnsignedShort((short) 0x7fff));
+
+ Assert.assertEquals(32768, NetUtils.getUnsignedShort((short) 0x8000));
+ Assert.assertEquals(65535, NetUtils.getUnsignedShort((short) 0xffff));
+ }
}
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.
@Override
public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
- List<FlowOnNode> currentStat = this.flowStatistics.get(node);
- // Update cache only if changed to avoid unnecessary cache sync operations
- if (! flowStatsList.equals(currentStat)){
- this.flowStatistics.put(node, flowStatsList);
- }
+ // No equality check because duration fields change constantly
+ this.flowStatistics.put(node, flowStatsList);
}
@Override
import org.opendaylight.controller.sal.utils.StatusCode;
/**
- * The class describes a switch configuration
+ * The class describes a switch configuration as a collection of properties
*/
public class SwitchConfig extends ConfigurationObject implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
}
private Status validateNodeId() {
- if (nodeId == null || nodeId.isEmpty()) {
- return new Status(StatusCode.BADREQUEST, "NodeId cannot be empty");
+ if (nodeId == null || nodeId.trim().isEmpty()) {
+ return new Status(StatusCode.BADREQUEST, "Invalid node id");
}
return new Status(StatusCode.SUCCESS);
}
private Status validateNodeProperties() {
if (nodeProperties == null) {
- return new Status(StatusCode.BADREQUEST, "nodeProperties cannot be null");
+ return new Status(StatusCode.BADREQUEST, "Node properties must be specified");
+ }
+ if (nodeProperties.containsKey(Description.propertyName)) {
+ if (!isValidResourceName(((Description)nodeProperties.get(Description.propertyName)).getValue())) {
+ return new Status(StatusCode.BADREQUEST, "Invalid node description");
+ }
}
return new Status(StatusCode.SUCCESS);
}
}
}
- 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;
}
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.List;
}
public List<String> getUserRoles() {
- return userRoles;
+ return userRoles == null ? Collections.<String> emptyList() : new ArrayList<String>(userRoles);
}
public void addUserRole(String string) {
package org.opendaylight.controller.usermanager;
+import java.util.Arrays;
+import java.util.List;
+
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.opendaylight.controller.sal.authorization.UserLevel;
import org.springframework.security.core.GrantedAuthority;
-import java.util.Arrays;
-import java.util.List;
-
public class AuthenticatedUserTest {
static String[] roleArray;
user = new AuthenticatedUser("auser");
Assert.assertFalse(user.getAccessDate().isEmpty());
- Assert.assertNull(user.getUserRoles());
+ Assert.assertNotNull(user.getUserRoles());
}
@Test
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
import org.opendaylight.controller.sal.match.MatchType;
import org.opendaylight.controller.sal.reader.FlowOnNode;
import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.reader.NodeDescription;
import org.opendaylight.controller.sal.utils.EtherTypes;
import org.opendaylight.controller.sal.utils.GlobalConstants;
import org.opendaylight.controller.sal.utils.HexEncode;
return userLevel.ordinal() <= AUTH_LEVEL.ordinal();
}
+ @RequestMapping(value = "/nodeInfo", method = RequestMethod.GET)
+ @ResponseBody
+ public NodeDescription getNodeInfo(HttpServletRequest request, @RequestParam(required = false) String container,
+ @RequestParam(required = true) String nodeId) {
+ List<Map<String, String>> lines = new ArrayList<Map<String, String>>();
+ String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+
+ // Derive the privilege this user has on the current container
+ String userName = request.getUserPrincipal().getName();
+ Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
+
+ if (privilege != Privilege.NONE) {
+ IStatisticsManager statisticsManager = (IStatisticsManager) ServiceHelper
+ .getInstance(IStatisticsManager.class, containerName, this);
+ if(statisticsManager != null){
+ Node node = Node.fromString(nodeId);
+ NodeDescription nodeDesc = statisticsManager.getNodeDescription(node);
+ return nodeDesc;
+ }
+ }
+
+ return new NodeDescription();
+ }
+
@RequestMapping(value = "/existingNodes", method = RequestMethod.GET)
@ResponseBody
public TroubleshootingJsonBean getExistingNodes(HttpServletRequest request, @RequestParam(required = false) String container) {
-/*
- * 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,
+/*
+ * 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
*
*/
/**Troubleshoot modules*/
one.f.troubleshooting = {
rootUrl: "/controller/web/troubleshoot",
- rightBottomDashlet: {
+ rightBottomDashlet: {
get: function() {
var $rightBottomDashlet = $("#right-bottom").find(".dashlet");
return $rightBottomDashlet;
},
setDashletHeader: function(label) {
- $("#right-bottom li a")[0].innerHTML = label;
+ $("#right-bottom li a")[0].innerHTML = label;
}
},
createTable: function(columnNames, body) {
portsDataGrid: "one_f_troubleshooting_existingNodes_id_portsDataGrid",
flowsDataGrid: "one_f_troubleshooting_existingNodes_id_flowsDataGrid",
refreshFlowsButton:"one_f_troubleshooting_existingNodes_id_refreshFlowsButton",
- refreshPortsButton:"one_f_troubleshooting_existingNodes_id_refreshPortsButton"
-
+ refreshPortsButton:"one_f_troubleshooting_existingNodes_id_refreshPortsButton",
+ modal : {
+ nodeInfo : "one_f_troubleshooting_existingNodes_id_modal_nodeInfo",
+ cancelButton : "one_f_troubleshooting_existingNodes_id_modal_cancelButton",
+ }
},
load: {
main: function($dashlet) {
$("#" + one.f.troubleshooting.existingNodes.id.portsDataGrid).datagrid({dataSource: dataSource});
});
} catch(e) {}
- }
+ }
},
ajax : function(url, callback) {
$.getJSON(url, function(data) {
data: data.nodeData,
formatter: function(items) {
$.each(items, function(index, item) {
- item["statistics"] = "<a href=\"javascript:one.f.troubleshooting.existingNodes.load.flows('" + item["nodeId"] + "');\">Flows</a>" +
+ item.nodeName = "<a href=\"javascript:one.f.troubleshooting.existingNodes.data.nodeInfo('"
+ + item.nodeId + "');\">" + item.nodeName + "</a>"
+ item["statistics"] = "<a href=\"javascript:one.f.troubleshooting.existingNodes.load.flows('" + item["nodeId"] + "');\">Flows</a>" +
" <a href=\"javascript:one.f.troubleshooting.existingNodes.load.ports('" + item["nodeId"] + "');\">Ports</a>";
});
},
result.push(tr);
});
return result;
+ },
+ nodeInfo : function(nodeId){
+ $.getJSON(one.main.constants.address.prefix + "/troubleshoot/nodeInfo?nodeId=" + nodeId, function(content) {
+ var h3 = 'Node Information'
+
+ var headers = [ 'Description','Specification'];
+
+ var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
+ var $table = one.lib.dashlet.table.table(attributes);
+ var $thead = one.lib.dashlet.table.header(headers);
+ $table.append($thead);
+
+ var footer = [];
+
+ var cancelButton = one.lib.dashlet.button.single("Cancel",
+ one.f.troubleshooting.existingNodes.id.modal.nodeInfo, "", "");
+ var $cancelButton = one.lib.dashlet.button.button(cancelButton);
+ footer.push($cancelButton);
+
+ var body = []
+ $.each(content, function(key, value) {
+ var tr = {};
+ var entry = [];
+
+ entry.push(key);
+ entry.push(value);
+
+ tr.entry = entry;
+ body.push(tr);
+ });
+ var $tbody = one.lib.dashlet.table.body(body);
+ $table.append($tbody);
+
+ var $modal = one.lib.modal.spawn(one.f.troubleshooting.existingNodes.id.modal.nodeInfo, h3, $table , footer);
+ $modal.modal();
+
+ $('#'+one.f.troubleshooting.existingNodes.id.modal.nodeInfo, $modal).click(function() {
+ $modal.modal('hide');
+ });
+ });
}
}
};
$("#" + one.f.troubleshooting.uptime.id.datagrid).datagrid({dataSource: dataSource});
});
},
-
+
ajax : {
main : function(url, requestData, callback) {
$.getJSON(url, requestData, function(data) {
});
}
},
-
+
data: {
uptimeDataGrid: function(data) {
var source = new StaticDataSource({
var $p = $(document.createElement('p'));
$p.text('Please select a Flow or Ports statistics');
$p.addClass('text-center').addClass('text-info');
-
+
$dashlet.append($none)
.append($p);
}