Bug-1517: Introduce topology data-change counter 15/10015/3
authorMilos Fabian <milfabia@cisco.com>
Sun, 17 Aug 2014 08:57:04 +0000 (10:57 +0200)
committerMilos Fabian <milfabia@cisco.com>
Fri, 22 Aug 2014 14:20:45 +0000 (16:20 +0200)
-registers DataChangeListener on specific topology
-increases counter on every "onDataChanged" invocation

-plugin contains sample initial configuration
-topology name is configurable
-can create only sole instance

-exposes data-change count via restconf:
GET "/restconf/operational/data-change-counter:data-change-counter"

Change-Id: I49665f059fa8db0c60491fef1f9424d0b0d87a6b
Signed-off-by: Milos Fabian <milfabia@cisco.com>
data-change-counter/.project [new file with mode: 0644]
data-change-counter/pom.xml [new file with mode: 0644]
data-change-counter/src/main/java/org/opendaylight/controller/config/yang/bgpcep/data/change/counter/DataChangeCounterImplModule.java [new file with mode: 0644]
data-change-counter/src/main/java/org/opendaylight/controller/config/yang/bgpcep/data/change/counter/DataChangeCounterImplModuleFactory.java [new file with mode: 0644]
data-change-counter/src/main/java/org/opendaylight/protocol/data/change/counter/TopologyDataChangeCounter.java [new file with mode: 0644]
data-change-counter/src/main/resources/initial/50-topology-data-change-counter.xml [new file with mode: 0644]
data-change-counter/src/main/yang/data-change-counter.yang [new file with mode: 0644]
data-change-counter/src/main/yang/odl-data-change-counter-cfg.yang [new file with mode: 0644]
data-change-counter/src/test/java/org/opendaylight/protocol/data/change/counter/TopologyDataChangeCounterTest.java [new file with mode: 0644]
pom.xml

diff --git a/data-change-counter/.project b/data-change-counter/.project
new file mode 100644 (file)
index 0000000..d85aca5
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>bgp-data-change-counter</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.m2e.core.maven2Builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.m2e.core.maven2Nature</nature>
+       </natures>
+</projectDescription>
diff --git a/data-change-counter/pom.xml b/data-change-counter/pom.xml
new file mode 100644 (file)
index 0000000..ea0a37c
--- /dev/null
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- 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 -->
+
+<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.bgpcep</groupId>
+    <artifactId>commons.parent</artifactId>
+    <version>0.3.1-SNAPSHOT</version>
+    <relativePath>../commons/parent</relativePath>
+  </parent>
+  <prerequisites>
+    <maven>3.0.4</maven>
+  </prerequisites>
+  <artifactId>data-change-counter</artifactId>
+  <packaging>bundle</packaging>
+  <name>${project.artifactId}</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-binding</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-common</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.yangtools.model</groupId>
+      <artifactId>ietf-topology</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-config</artifactId>
+    </dependency>
+
+    <!-- test dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-broker-impl</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-broker-impl</artifactId>
+      <scope>test</scope>
+      <type>test-jar</type>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yang-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/data-change-counter/src/main/java/org/opendaylight/controller/config/yang/bgpcep/data/change/counter/DataChangeCounterImplModule.java b/data-change-counter/src/main/java/org/opendaylight/controller/config/yang/bgpcep/data/change/counter/DataChangeCounterImplModule.java
new file mode 100644 (file)
index 0000000..171c295
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.config.yang.bgpcep.data.change.counter;
+
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.protocol.data.change.counter.TopologyDataChangeCounter;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class DataChangeCounterImplModule extends org.opendaylight.controller.config.yang.bgpcep.data.change.counter.AbstractDataChangeCounterImplModule {
+
+    public DataChangeCounterImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public DataChangeCounterImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            org.opendaylight.controller.config.yang.bgpcep.data.change.counter.DataChangeCounterImplModule oldModule,
+            java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        JmxAttributeValidationException.checkNotNull(getTopologyName(), "value is not set.", topologyNameJmxAttribute);
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        final TopologyDataChangeCounter counter = new TopologyDataChangeCounter(getDataProviderDependency());
+        final InstanceIdentifier<Topology> topoIId = InstanceIdentifier.builder(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(new TopologyId(getTopologyName()))).toInstance();
+        final ListenerRegistration<DataChangeListener> registration = getDataProviderDependency().registerDataChangeListener(
+                LogicalDatastoreType.OPERATIONAL, topoIId, counter, DataBroker.DataChangeScope.SUBTREE);
+        return new DataChangeCounterCloseable(counter, registration);
+    }
+
+    private final class DataChangeCounterCloseable implements AutoCloseable {
+
+        private final TopologyDataChangeCounter inner;
+        private final ListenerRegistration<DataChangeListener> registration;
+
+        public DataChangeCounterCloseable(TopologyDataChangeCounter inner,
+                ListenerRegistration<DataChangeListener> registration) {
+            this.inner = inner;
+            this.registration = registration;
+        }
+
+        @Override
+        public void close() throws Exception {
+            this.registration.close();
+            this.inner.close();
+        }
+    }
+
+}
diff --git a/data-change-counter/src/main/java/org/opendaylight/controller/config/yang/bgpcep/data/change/counter/DataChangeCounterImplModuleFactory.java b/data-change-counter/src/main/java/org/opendaylight/controller/config/yang/bgpcep/data/change/counter/DataChangeCounterImplModuleFactory.java
new file mode 100644 (file)
index 0000000..609e0fb
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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
+ */
+
+/*
+* Generated file
+*
+* Generated from: yang module name: odl-data-change-counter-cfg yang module local name: data-change-counter-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Aug 20 13:09:16 CEST 2014
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.bgpcep.data.change.counter;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.osgi.framework.BundleContext;
+
+public class DataChangeCounterImplModuleFactory extends org.opendaylight.controller.config.yang.bgpcep.data.change.counter.AbstractDataChangeCounterImplModuleFactory {
+    public static final String SINGLETON_NAME = "data-change-counter-singleton";
+
+    @Override
+    public DataChangeCounterImplModule instantiateModule(String instanceName, DependencyResolver dependencyResolver,
+            DataChangeCounterImplModule oldModule, AutoCloseable oldInstance, BundleContext bundleContext) {
+        checkArgument(SINGLETON_NAME.equals(instanceName), "Illegal instance name '" + instanceName
+                + "', only allowed name is " + SINGLETON_NAME);
+        return super.instantiateModule(instanceName, dependencyResolver, oldModule,
+                oldInstance, bundleContext);
+    }
+
+    @Override
+    public DataChangeCounterImplModule instantiateModule(String instanceName, DependencyResolver dependencyResolver,
+            BundleContext bundleContext) {
+        checkArgument(SINGLETON_NAME.equals(instanceName), "Illegal instance name '" + instanceName
+                + "', only allowed name is " + SINGLETON_NAME);
+        return super.instantiateModule(instanceName, dependencyResolver, bundleContext);
+    }
+}
diff --git a/data-change-counter/src/main/java/org/opendaylight/protocol/data/change/counter/TopologyDataChangeCounter.java b/data-change-counter/src/main/java/org/opendaylight/protocol/data/change/counter/TopologyDataChangeCounter.java
new file mode 100644 (file)
index 0000000..2ce311a
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.protocol.data.change.counter;
+
+import java.util.concurrent.atomic.AtomicLong;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.data.change.counter.rev140815.DataChangeCounter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.data.change.counter.rev140815.DataChangeCounterBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TopologyDataChangeCounter implements DataChangeListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TopologyDataChangeCounter.class);
+
+    protected static final InstanceIdentifier<DataChangeCounter> IID = InstanceIdentifier
+            .builder(DataChangeCounter.class).toInstance();
+
+    private final DataBroker dataBroker;
+    private AtomicLong count;
+
+    public TopologyDataChangeCounter(final DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+        this.count = new AtomicLong(0);
+        putCount(this.count.get());
+        LOG.debug("Data change counter initiated");
+    }
+
+    @Override
+    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        putCount(this.count.incrementAndGet());
+        LOG.debug("Data change #{}", this.count.get());
+    }
+
+    public void close() {
+        final WriteTransaction wTx = this.dataBroker.newWriteOnlyTransaction();
+        wTx.delete(LogicalDatastoreType.OPERATIONAL, IID);
+        wTx.submit();
+        LOG.debug("Data change counter removed");
+    }
+
+    private void putCount(final long count) {
+        final WriteTransaction wTx = this.dataBroker.newWriteOnlyTransaction();
+        wTx.put(LogicalDatastoreType.OPERATIONAL, IID, new DataChangeCounterBuilder().setCount(count)
+                .build());
+        wTx.submit();
+    }
+
+}
diff --git a/data-change-counter/src/main/resources/initial/50-topology-data-change-counter.xml b/data-change-counter/src/main/resources/initial/50-topology-data-change-counter.xml
new file mode 100644 (file)
index 0000000..51276a9
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+      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
+-->
+<snapshot>
+    <required-capabilities>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:bgpcep:data:change:counter?module=odl-data-change-counter-cfg&amp;revision=2014-08-15</capability>
+    </required-capabilities>
+    <configuration>
+
+        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <module>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:bgpcep:data:change:counter">prefix:data-change-counter-impl</type>
+                    <name>data-change-counter-singleton</name>
+                    <data-provider>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+                        <name>binding-data-broker</name>
+                    </data-provider>
+                    <topology-name>example-linkstate-topology</topology-name>
+                </module>
+            </modules>
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+            </services>
+        </data>
+
+    </configuration>
+</snapshot>
diff --git a/data-change-counter/src/main/yang/data-change-counter.yang b/data-change-counter/src/main/yang/data-change-counter.yang
new file mode 100644 (file)
index 0000000..c60cf6b
--- /dev/null
@@ -0,0 +1,32 @@
+module data-change-counter {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:bgp-data-change-counter";
+    prefix "bgp-dcc";
+
+    organization "Cisco Systems, Inc.";
+    contact "Milos Fabian <milfabia@cisco.com>";
+
+    description
+        "This module contains the base data model of a topology
+        data-change counter. The module servers for testing purposes.
+
+        Copyright (c)2014 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-08-15" {
+        description
+            "Initial revision.";
+    }
+
+    container data-change-counter {
+        leaf count {
+            type uint32;
+            description
+                "The number of data changes.";
+        }
+    }
+ }
\ No newline at end of file
diff --git a/data-change-counter/src/main/yang/odl-data-change-counter-cfg.yang b/data-change-counter/src/main/yang/odl-data-change-counter-cfg.yang
new file mode 100644 (file)
index 0000000..5383e91
--- /dev/null
@@ -0,0 +1,53 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module odl-data-change-counter-cfg {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:bgpcep:data:change:counter";
+    prefix "dcc-cfg";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+
+    organization "Cisco Systems, Inc.";
+
+    contact "Milos Fabian <milfabia@cisco.com>";
+
+    description
+        "This module contains the base YANG definitions for
+         topology data-change counter.
+
+        Copyright (c)2014 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-08-15" {
+        description
+            "Initial revision";
+    }
+
+    identity data-change-counter-impl {
+        base config:module-type;
+        config:java-name-prefix DataChangeCounterImpl;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case data-change-counter-impl {
+            when "/config:modules/config:module/config:type = 'data-change-counter-impl'";
+
+            leaf topology-name {
+                type string;
+            }
+
+            container data-provider {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-async-data-broker;
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/data-change-counter/src/test/java/org/opendaylight/protocol/data/change/counter/TopologyDataChangeCounterTest.java b/data-change-counter/src/test/java/org/opendaylight/protocol/data/change/counter/TopologyDataChangeCounterTest.java
new file mode 100644 (file)
index 0000000..bfc042f
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.protocol.data.change.counter;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Optional;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.data.change.counter.rev140815.DataChangeCounter;
+
+public class TopologyDataChangeCounterTest extends AbstractDataBrokerTest {
+
+    @Test
+    public void testDataChangeCounter() throws InterruptedException, ExecutionException {
+        final TopologyDataChangeCounter counter = new TopologyDataChangeCounter(getDataBroker());
+        final Optional<Long> count = getCount();
+        assertTrue(count.isPresent());
+        assertEquals(0, count.get().longValue());
+
+        counter.onDataChanged(null);
+        final Optional<Long> countAfterDataChange = getCount();
+        assertTrue(countAfterDataChange.isPresent());
+        assertEquals(1, countAfterDataChange.get().longValue());
+
+        counter.close();
+        final Optional<Long> countAfterClose = getCount();
+        assertFalse(countAfterClose.isPresent());
+    }
+
+    private Optional<Long> getCount() throws InterruptedException, ExecutionException {
+        final ReadTransaction rTx = getDataBroker().newReadOnlyTransaction();
+        final Optional<DataChangeCounter> dataMaybe = rTx.read(LogicalDatastoreType.OPERATIONAL, TopologyDataChangeCounter.IID).get();
+        if (dataMaybe.isPresent()) {
+            return Optional.of(dataMaybe.get().getCount());
+        }
+        return Optional.absent();
+    }
+}
diff --git a/pom.xml b/pom.xml
index aa952acadaebeebbe7ea62e2b45f09048f2efd3e..ef267a6c9090422e649156b173aec33ce6720370 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -44,6 +44,9 @@
         <!-- Integration tests -->
         <module>integration-tests</module>
 
+        <!--Test tools -->
+        <module>data-change-counter</module>
+
         <!-- Parents -->
         <module>commons/parent</module>
     </modules>