Bug 1484 - StatisticManager performance improvement refactoring 05/10605/23
authorVaclav Demcak <vdemcak@cisco.com>
Wed, 17 Sep 2014 00:53:03 +0000 (02:53 +0200)
committerVaclav Demcak <vdemcak@cisco.com>
Mon, 22 Sep 2014 20:16:12 +0000 (22:16 +0200)
* migration to new MD-SAL API (DataBroker DataChangeListener)
* splitting project api/impl + (javaDoc for api)
* clean pom.xml (xtend dependency and private-package, add sal-binding-broker-impl for test)
* chaining req/resp StatisticNotification per FlowNode per statistic for prevent DS and RPC queue overload
* add multipart msg joiner (StatManager wait for all relevant multipart msg for notification before write relevant
Oper/DS action) - possibility to remove all not used subtrees (target -> reflect actual device contain asap for
all alien node's data).
* add FlowNode registratration - registration needs all SwitchFuture information for make a correct Stat target list (flows,
groups, meters, queues, tables, nrOfTables, ports) - fix for sending not supported notifications to device
* add logic for unique identification FlowId - DeviceFlow (create unique tweens FlowId and flowHash from responded device
flow fields like match, priority, flowCookie, flowCookieMask)
* change FlowCookieMap to FlowHashMap -> List<FlowHash, FlowId>
* implement parallel statistics collecting for FlowCapableNode Sets
* add MockTestSuite for a StatManager workflow interaction testing (neet to be fixed for newest changes)

PASS tests https://jenkins.opendaylight.org/integration/job/integration-master-csit-base-of13
PASS tests https://jenkins.opendaylight.org/integration/job/integration-master-csit-karaf-l2switch-only/
PASS tests https://jenkins.opendaylight.org/integration/job/integration-master-csit-karaf-compatible-min/

Change-Id: I265b57378fc19573d6f18036825cb57f4131ca80
Signed-off-by: Jan Hajnar <jhajnar@cisco.com>
Signed-off-by: Vaclav Demcak <vdemcak@cisco.com>
74 files changed:
opendaylight/karaf-branding/pom.xml
opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang
opendaylight/md-sal/statistics-manager/pom.xml
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatListeningCommiter.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatNodeRegistration.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatNotifyCommiter.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatPermCollector.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatRpcMsgManager.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManager.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatAbstractListenCommit.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatAbstractNotifyCommit.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitFlow.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitGroup.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitMeter.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitQueue.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNodeRegistrationImpl.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNotifyCommitPort.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNotifyCommitTable.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatPermCollectorImpl.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatRPCFailedException.java [moved from opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java with 75% similarity]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatRpcMsgManagerImpl.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatisticsManagerImpl.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/helper/FlowComparator.java [moved from opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java with 80% similarity]
opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerProvider.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/impl/helper/StatisticsUpdateCommiterTest.java [moved from opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java with 81% similarity]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/FlowStatisticsTest.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/GroupStatisticsTest.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/MeterStatisticsTest.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/NodeRegistrationTest.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/PortStatisticsTest.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/QueueStatisticsTest.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/TableStatisticsTest.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/AbstractDataBrokerTest.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/AbstractSchemaAwareTest.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/BundleContextMock.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/DataBrokerTestCustomizer.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/FlowMockGenerator.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/GroupMockGenerator.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/MatchMockGenerator.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/MeterMockGenerator.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/MockSchemaService.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/NotificationProviderServiceHelper.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightFlowStatisticsServiceMock.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightFlowTableStatisticsServiceMock.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightGroupStatisticsServiceMock.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightMeterStatisticsServiceMock.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightPortStatisticsServiceMock.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/OpendaylightQueueStatisticsServiceMock.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/PortMockGenerator.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/ProviderContextMock.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/QueueMockGenerator.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/RpcProviderRegistryMock.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/StatisticsManagerTest.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/java/test/mock/util/TestUtils.java [new file with mode: 0644]

index 444e770..722bdea 100644 (file)
@@ -1,39 +1,37 @@
 <?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>releasepom</artifactId>
-      <version>0.1.2-SNAPSHOT</version>
-      <relativePath>../..</relativePath>
-    </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>karaf.branding</artifactId>
-    <version>1.0.0-SNAPSHOT</version>
-    <packaging>bundle</packaging>
-    <name>OpenDaylight :: Karaf :: Branding</name>
+    <artifactId>releasepom</artifactId>
+    <version>0.1.2-SNAPSHOT</version>
+    <relativePath>../..</relativePath>
+  </parent>
+  <groupId>org.opendaylight.controller</groupId>
+  <artifactId>karaf.branding</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+  <name>OpenDaylight :: Karaf :: Branding</name>
 
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <version>2.4.0</version>
-                <extensions>true</extensions>
-                <configuration>
-                    <instructions>
-                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
-                        <Import-Package>*</Import-Package>
-                        <Private-Package>!*</Private-Package>
-                        <Export-Package>
-                            org.apache.karaf.branding
-                        </Export-Package>
-                        <Spring-Context>*;public-context:=false</Spring-Context>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.4.0</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+            <Import-Package>*</Import-Package>
+            <Private-Package>!*</Private-Package>
+            <Export-Package>org.apache.karaf.branding</Export-Package>
+            <Spring-Context>*;public-context:=false</Spring-Context>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
 
 </project>
index 5a40022..fc0eb4c 100644 (file)
@@ -236,13 +236,17 @@ module flow-node-inventory {
     }
 
     augment "/inv:nodes/inv:node/table" {
-        ext:augment-identifier "flow-cookie-mapping";
-        list flow-cookie-map {
-            key "cookie";
-            leaf cookie {
-                type flow:flow-cookie;
+        ext:augment-identifier "flow-hash-id-mapping";
+    description "Flow is identified by match and priority on device. So Operational/DS
+        has to simulate that behavior and contract between FlowId and match+priority
+        identification should represent Flow hashCode. Flow has to contain only
+        match priority and flowCookie for create a hashCode";
+        list flow-hash-id-map {
+            key "hash";
+            leaf hash {
+                type string;
             }
-            leaf-list flow-ids {
+            leaf flow-id {
                 type flow-id;
             }
         }
index 399d53b..5b8c626 100644 (file)
@@ -21,8 +21,9 @@
       <artifactId>junit</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.xtend</groupId>
-      <artifactId>org.eclipse.xtend.lib</artifactId>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-broker-impl</artifactId>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
@@ -57,7 +58,6 @@
         <configuration>
           <instructions>
             <Bundle-Activator>org.opendaylight.controller.md.statistics.manager.StatisticsManagerActivator</Bundle-Activator>
-            <Private-Package>org.opendaylight.controller.md.statistics.manager</Private-Package>
           </instructions>
         </configuration>
       </plugin>
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java
deleted file mode 100644 (file)
index 167fb21..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.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) {
-        super(context);
-    }
-
-    protected abstract InstanceIdentifier<?> listenPath();
-    protected abstract String statName();
-
-    public void start(final DataBrokerService dbs) {
-        Preconditions.checkState(reg == null);
-
-        reg = dbs.registerDataChangeListener(listenPath(), this);
-        logger.debug("{} Statistics tracker for node {} started", statName(), getNodeIdentifier());
-    }
-
-    @Override
-    public final void close() {
-        if (reg != null) {
-            try {
-                reg.close();
-            } catch (Exception e) {
-                logger.warn("Failed to stop {} Statistics tracker for node {}", statName(), getNodeIdentifier(), e);
-            }
-            reg = null;
-        }
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java
deleted file mode 100644 (file)
index 838aeb7..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.util.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 static final int WAIT_FOR_REQUEST_CYCLE = 2;
-
-    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 long requestCounter;
-
-    protected AbstractStatsTracker(final FlowCapableContext context) {
-        this.context = Preconditions.checkNotNull(context);
-        this.requestCounter = 0;
-    }
-
-    protected final InstanceIdentifierBuilder<Node> getNodeIdentifierBuilder() {
-        return getNodeIdentifier().builder();
-    }
-
-    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();
-    }
-
-    public final synchronized void increaseRequestCounter(){
-        this.requestCounter++;
-    }
-    protected abstract void cleanupSingleStat(DataModificationTransaction trans, K item);
-    protected abstract K updateSingleStat(DataModificationTransaction trans, I item);
-    protected abstract K createInvariantKey(K item);
-    public abstract void request();
-
-    public final synchronized void updateStats(List<I> list) {
-
-        final DataModificationTransaction trans = startTransaction();
-        for (final I item : list) {
-            K key = updateSingleStat(trans, item);
-            trackedItems.put(createInvariantKey(key), requestCounter);
-        }
-
-        trans.commit();
-    }
-
-    /**
-     * Statistics will be cleaned up if not update in last two request cycles.
-     * @param trans
-     */
-    public final synchronized void cleanup(final DataModificationTransaction trans) {
-        for (Iterator<Entry<K, Long>> it = trackedItems.entrySet().iterator();it.hasNext();){
-            Entry<K, Long> e = it.next();
-            if (requestCounter >= e.getValue()+WAIT_FOR_REQUEST_CYCLE) {
-                cleanupSingleStat(trans, e.getKey());
-                it.remove();
-            }
-        }
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java
deleted file mode 100644 (file)
index 520b344..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.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);
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java
deleted file mode 100644 (file)
index bb1544c..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.util.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);
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java
deleted file mode 100644 (file)
index c43c1eb..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import 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;
-    }
-
-    @Override
-    public String toString() {
-        return "FlowStatsEntry [tableId=" + tableId + ", flow=" + flow + "]";
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java
deleted file mode 100644 (file)
index d540f11..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.math.BigInteger;
-import java.util.Collection;
-import java.util.Collections;
-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.FlowCookieMapping;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMap;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMapBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMapKey;
-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.flow.types.rev131026.FlowCookie;
-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.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Optional;
-
-final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatisticsMapList, FlowStatsEntry> {
-    private static final Logger LOG = LoggerFactory.getLogger(FlowStatsTracker.class);
-    private static final String ALIEN_SYSTEM_FLOW_ID = "#UF$TABLE*";
-    private final OpendaylightFlowStatisticsService flowStatsService;
-    private FlowTableStatsTracker flowTableStats;
-    private int unaccountedFlowsCounter = 1;
-
-
-    FlowStatsTracker(final OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context) {
-        super(context);
-        this.flowStatsService = flowStatsService;
-    }
-    FlowStatsTracker(final OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context, final FlowTableStatsTracker flowTableStats) {
-        this(flowStatsService, context);
-        this.flowTableStats = flowTableStats;
-    }
-
-    @Override
-    protected void cleanupSingleStat(final DataModificationTransaction trans, final FlowStatsEntry item) {
-        KeyedInstanceIdentifier<Flow, FlowKey> flowRef = getNodeIdentifier()
-                .augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(item.getTableId()))
-                .child(Flow.class, item.getFlow().getKey());
-        trans.removeOperationalData(flowRef);
-    }
-
-    @Override
-    protected FlowStatsEntry updateSingleStat(final DataModificationTransaction trans, final FlowAndStatisticsMapList map) {
-        short tableId = map.getTableId();
-
-        FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
-
-        FlowBuilder flowBuilder = new FlowBuilder(map);
-        if (map.getFlowId() != null) {
-            flowBuilder.setId(new FlowId(map.getFlowId().getValue()));
-        }
-        if (map.getFlowId() != null) {
-            flowBuilder.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
-        }
-
-        Flow flowRule = flowBuilder.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());
-
-        flowStatisticsData.setFlowStatistics(flowStatistics.build());
-
-        LOG.debug("Flow : {}",flowRule.toString());
-        LOG.debug("Statistics to augment : {}",flowStatistics.build().toString());
-
-        InstanceIdentifier<Table> tableRef = getNodeIdentifierBuilder()
-                .augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(tableId)).toInstance();
-
-        final FlowCookie flowCookie = flowRule.getCookie() != null
-                ? flowRule.getCookie() : new FlowCookie(BigInteger.ZERO);
-        final InstanceIdentifier<FlowCookieMap> flowCookieRef = tableRef
-                .augmentation(FlowCookieMapping.class)
-                .child(FlowCookieMap.class, new FlowCookieMapKey(flowCookie));
-
-        FlowCookieMap cookieMap = (FlowCookieMap) trans.readOperationalData(flowCookieRef);
-
-        /* find flowKey in FlowCookieMap from DataStore/OPERATIONAL */
-        Optional<FlowKey> flowKey = this.getExistFlowKey(flowRule, tableRef, trans, cookieMap);
-        if ( ! flowKey.isPresent()) {
-            /* DataStore/CONFIG For every first statistic needs to be created */
-            flowKey = this.getFlowKeyFromExistFlow(flowRule, tableRef, trans);
-            if ( ! flowKey.isPresent()) {
-                /* Alien flow */
-                flowKey = this.makeAlienFlowKey(flowRule);
-            }
-            cookieMap = applyNewFlowKey(cookieMap, flowKey, flowCookie);
-            trans.putOperationalData(flowCookieRef, cookieMap);
-        }
-
-        InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder()
-                .augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(tableId))
-                .child(Flow.class, flowKey.get()).toInstance();
-        flowBuilder.setKey(flowKey.get());
-        flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
-
-        // Update entry with timestamp of latest response
-        flowBuilder.setKey(flowKey.get());
-        FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId, flowBuilder.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";
-    }
-
-    @Override
-    public void 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();
-        LOG.debug("Node {} supports {} table(s)", this.getNodeRef(), tables.size());
-        for (final TableKey key : tables) {
-            LOG.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), this.getNodeRef());
-            this.requestAggregateFlows(key);
-        }
-
-        this.requestAllFlowsAllTables();
-
-    }
-    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(final 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();
-                LOG.debug("Key {} triggered request for flow {}", e.getKey(), flow);
-                requestFlow(flow);
-            } else {
-                LOG.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;
-                LOG.debug("Key {} triggered remove of Flow from operational space.", key);
-                trans.removeOperationalData(flow);
-            }
-        }
-        trans.commit();
-    }
-
-    @Override
-    public void start(final DataBrokerService dbs) {
-        if (flowStatsService == null) {
-            LOG.debug("No Flow Statistics service, not subscribing to flows on node {}", getNodeIdentifier());
-            return;
-        }
-
-        super.start(dbs);
-    }
-
-    /* Returns Exist FlowKey from exist FlowCookieMap identified by cookie
-     * and by switch flow identification (priority and match)*/
-    private Optional<FlowKey> getExistFlowKey(final Flow flowRule, final InstanceIdentifier<Table> tableRef,
-            final DataModificationTransaction trans, final FlowCookieMap cookieMap) {
-
-        if (cookieMap != null) {
-            for (FlowId flowId : cookieMap.getFlowIds()) {
-                InstanceIdentifier<Flow> flowIdent = tableRef.child(Flow.class, new FlowKey(flowId));
-                if (flowId.getValue().startsWith(ALIEN_SYSTEM_FLOW_ID)) {
-                    LOG.debug("Search for flow in the operational datastore by flowID: {} ", flowIdent);
-                    Flow readedFlow = (Flow) trans.readOperationalData(flowIdent);
-                    if (FlowComparator.flowEquals(flowRule, readedFlow)) {
-                        return Optional.<FlowKey> of(new FlowKey(flowId));
-                    }
-                } else {
-                    LOG.debug("Search for flow in the configuration datastore by flowID: {} ", flowIdent);
-                    Flow readedFlow = (Flow) trans.readConfigurationData(flowIdent);
-                    if (FlowComparator.flowEquals(flowRule, readedFlow)) {
-                        return Optional.<FlowKey> of(new FlowKey(flowId));
-                    }
-                }
-            }
-            LOG.debug("Flow was not found in the datastore. Flow {} ", flowRule);
-        }
-        return Optional.absent();
-    }
-
-    /* Returns FlowKey from existing Flow in DataStore/CONFIGURATIONAL which is identified by cookie
-     * and by switch flow identification (priority and match) */
-    private Optional<FlowKey> getFlowKeyFromExistFlow(final Flow flowRule, final InstanceIdentifier<Table> tableRef,
-            final DataModificationTransaction trans) {
-
-        /* Try to find it in DataSotre/CONFIG */
-        Table table= (Table)trans.readConfigurationData(tableRef);
-        if(table != null) {
-            for(Flow existingFlow : table.getFlow()) {
-                LOG.debug("Existing flow in data store : {}",existingFlow.toString());
-                if(FlowComparator.flowEquals(flowRule,existingFlow)){
-                    return Optional.<FlowKey> of(new FlowKey(existingFlow.getId()));
-                }
-            }
-        }
-        return Optional.absent();
-    }
-
-    /* Returns FlowKey which doesn't exist in any DataStore for now */
-    private Optional<FlowKey> makeAlienFlowKey(final Flow flowRule) {
-
-        StringBuilder sBuilder = new StringBuilder(ALIEN_SYSTEM_FLOW_ID)
-            .append(flowRule.getTableId()).append("-").append(this.unaccountedFlowsCounter);
-        this.unaccountedFlowsCounter++;
-        final FlowId flowId = new FlowId(sBuilder.toString());
-        return Optional.<FlowKey> of(new FlowKey(flowId));
-    }
-
-    /* Build new whole FlowCookieMap or add new flowKey */
-    private FlowCookieMap applyNewFlowKey(FlowCookieMap flowCookieMap, final Optional<FlowKey> flowKey,
-            final FlowCookie flowCookie) {
-        if (flowCookieMap != null) {
-            flowCookieMap.getFlowIds().add(flowKey.get().getId());
-        } else {
-            final FlowCookieMapBuilder flowCookieMapBuilder = new FlowCookieMapBuilder();
-            flowCookieMapBuilder.setCookie(flowCookie);
-            flowCookieMapBuilder.setFlowIds(Collections.singletonList(flowKey.get().getId()));
-            flowCookieMap = flowCookieMapBuilder.build();
-        }
-        return flowCookieMap;
-    }
-
-    @Override
-    protected FlowStatsEntry createInvariantKey(final FlowStatsEntry item) {
-        FlowBuilder newFlow = new FlowBuilder();
-        newFlow.setId(item.getFlow().getId());
-        newFlow.setKey(item.getFlow().getKey());
-        newFlow.fieldsFrom(item.getFlow());
-        return new FlowStatsEntry(item.getTableId(),newFlow.build());
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java
deleted file mode 100644 (file)
index 2e85058..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.util.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.and.statistics.map.FlowTableAndStatisticsMapBuilder;
-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) {
-        super(context);
-        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;
-    }
-
-    @Override
-    public void request() {
-        if (flowTableStatsService != null) {
-            final GetFlowTablesStatisticsInputBuilder input = new GetFlowTablesStatisticsInputBuilder();
-            input.setNode(getNodeRef());
-
-            requestHelper(flowTableStatsService.getFlowTablesStatistics(input.build()));
-        }
-    }
-
-    @Override
-    protected FlowTableAndStatisticsMap createInvariantKey(FlowTableAndStatisticsMap item) {
-        FlowTableAndStatisticsMapBuilder flowTableAndStatisticsMapBuilder = new FlowTableAndStatisticsMapBuilder();
-        flowTableAndStatisticsMapBuilder.setTableId(item.getTableId());
-        flowTableAndStatisticsMapBuilder.setKey(item.getKey());
-        return flowTableAndStatisticsMapBuilder.build();
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java
deleted file mode 100644 (file)
index 11c6d4c..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import 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) {
-        super(context);
-        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";
-    }
-
-    @Override
-    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 = group.augmentation(NodeGroupDescStats.class);
-                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);
-    }
-
-    @Override
-    protected GroupDescStats createInvariantKey(GroupDescStats item) {
-        // No invariant data exist in the group description stats.
-        return item;
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java
deleted file mode 100644 (file)
index f3ba456..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import 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.group.statistics.reply.GroupStatsBuilder;
-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) {
-        super(context);
-        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";
-    }
-
-    @Override
-    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 = group.augmentation(NodeGroupStatistics.class);
-                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);
-    }
-
-    @Override
-    protected GroupStats createInvariantKey(GroupStats item) {
-        GroupStatsBuilder groupStatsBuilder = new GroupStatsBuilder();
-        groupStatsBuilder.setKey(item.getKey());
-        groupStatsBuilder.setGroupId(item.getGroupId());
-        return groupStatsBuilder.build();
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java
deleted file mode 100644 (file)
index 88139fc..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import 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) {
-        super(context);
-        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;
-    }
-
-    @Override
-    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 =
-                        meter.augmentation(NodeMeterConfigStats.class);
-                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);
-    }
-
-    @Override
-    protected MeterConfigStats createInvariantKey(MeterConfigStats item) {
-        // No invariant data exist in the meter config stats.
-        return item;
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java
deleted file mode 100644 (file)
index f43ec69..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import 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.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStatsBuilder;
-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) {
-        super(context);
-        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;
-    }
-
-    @Override
-    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 =
-                        meter.augmentation(NodeMeterStatistics.class);
-                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);
-    }
-
-    @Override
-    protected MeterStats createInvariantKey(MeterStats item) {
-        MeterStatsBuilder meterStatsBuilder = new MeterStatsBuilder();
-        meterStatsBuilder.setKey(item.getKey());
-        meterStatsBuilder.setMeterId(item.getMeterId());
-        return meterStatsBuilder.build();
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java
deleted file mode 100644 (file)
index 425a449..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.MultipartTransactionAware;
-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 com.google.common.base.Preconditions;
-
-/**
- * Main responsibility of the class is to manage multipart response
- * for multipart request. It also handles the flow aggregate request
- * and response mapping.
- * @author avishnoi@in.ibm.com
- *
- */
-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.
-     */
-    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 final Map<TxIdEntry,Short> txIdTotableIdMap = new ConcurrentHashMap<>();
-    private final long lifetimeNanos;
-
-    public MultipartMessageManager(long lifetimeNanos) {
-        this.lifetimeNanos = lifetimeNanos;
-    }
-
-    private static final class TxIdEntry {
-        private final TransactionId txId;
-
-        public TxIdEntry(TransactionId txId) {
-            this.txId = txId;
-        }
-        public TransactionId getTxId() {
-            return txId;
-        }
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((txId == null) ? 0 : txId.hashCode());
-            return result;
-        }
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj == null) {
-                return false;
-            }
-            if (!(obj instanceof TxIdEntry)) {
-                return false;
-            }
-            TxIdEntry other = (TxIdEntry) obj;
-
-            if (txId == null) {
-                if (other.txId != null) {
-                    return false;
-                }
-            } else if (!txId.equals(other.txId)) {
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public String toString() {
-            return "TxIdEntry [txId=" + txId + ']';
-        }
-    }
-
-    public void recordExpectedTableTransaction(TransactionId id, Short tableId) {
-        recordExpectedTransaction(id);
-        txIdTotableIdMap.put(new TxIdEntry(id), Preconditions.checkNotNull(tableId));
-    }
-
-    public Short isExpectedTableTransaction(TransactionAware transaction) {
-        Boolean more = null;
-        if (transaction instanceof MultipartTransactionAware) {
-            more = ((MultipartTransactionAware)transaction).isMoreReplies();
-        }
-
-        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 recordExpectedTransaction(TransactionId id) {
-        TxIdEntry entry = new TxIdEntry(Preconditions.checkNotNull(id));
-        txIdToRequestTypeMap.put(entry, getExpiryTime());
-    }
-
-    private boolean isExpectedTransaction(TransactionAware transaction, Boolean more) {
-        final TxIdEntry entry = new TxIdEntry(transaction.getTransactionId());
-        if (more != null && more.booleanValue()) {
-            return txIdToRequestTypeMap.containsKey(entry);
-        } else {
-            return txIdToRequestTypeMap.remove(entry) != null;
-        }
-    }
-
-    public boolean isExpectedTransaction(TransactionAware transaction) {
-        Boolean more = null;
-        if (transaction instanceof MultipartTransactionAware) {
-            more = ((MultipartTransactionAware)transaction).isMoreReplies();
-        }
-
-        return isExpectedTransaction(transaction, more);
-    }
-
-    private Long getExpiryTime() {
-        return System.nanoTime() + lifetimeNanos;
-    }
-
-    public void cleanStaleTransactionIds() {
-        final long now = System.nanoTime();
-
-        for (Iterator<TxIdEntry> it = txIdToRequestTypeMap.keySet().iterator();it.hasNext();){
-            TxIdEntry txIdEntry = it.next();
-
-            Long expiryTime = txIdToRequestTypeMap.get(txIdEntry);
-            if(now > expiryTime){
-                it.remove();
-                txIdTotableIdMap.remove(txIdEntry);
-            }
-        }
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java
deleted file mode 100644 (file)
index 2e2bf1c..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import 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.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMapBuilder;
-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) {
-        super(context);
-        this.portStatsService = portStatsService;
-    }
-
-    @Override
-    protected void cleanupSingleStat(final DataModificationTransaction trans, final NodeConnectorStatisticsAndPortNumberMap item) {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    protected NodeConnectorStatisticsAndPortNumberMap updateSingleStat(final DataModificationTransaction trans, final 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());
-
-        final NodeConnectorKey key = new NodeConnectorKey(item.getNodeConnectorId());
-        final InstanceIdentifier<NodeConnector> nodeConnectorRef = getNodeIdentifier().child(NodeConnector.class, key);
-
-        // 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()
-                .setKey(key).setId(item.getNodeConnectorId())
-                .addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats);
-            trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
-        }
-
-        return item;
-    }
-
-    @Override
-    public void request() {
-        if (portStatsService != null) {
-            final GetAllNodeConnectorsStatisticsInputBuilder input = new GetAllNodeConnectorsStatisticsInputBuilder();
-            input.setNode(getNodeRef());
-
-            requestHelper(portStatsService.getAllNodeConnectorsStatistics(input.build()));
-        }
-    }
-
-    @Override
-    protected NodeConnectorStatisticsAndPortNumberMap createInvariantKey(NodeConnectorStatisticsAndPortNumberMap item) {
-        NodeConnectorStatisticsAndPortNumberMapBuilder ncStatsBuilder = new NodeConnectorStatisticsAndPortNumberMapBuilder();
-        ncStatsBuilder.setNodeConnectorId(item.getNodeConnectorId());
-        ncStatsBuilder.setKey(item.getKey());
-        return ncStatsBuilder.build();
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java
deleted file mode 100644 (file)
index db21623..0000000
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.util.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 StatisticsRequestScheduler srScheduler;
-    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() {
-            try{
-                requestPeriodicStatistics();
-                cleanStaleStatistics();
-            }catch(Exception e){
-                logger.warn("Exception occured while sending statistics request : {}",e);
-            }
-        }
-    };
-
-    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,
-            final StatisticsRequestScheduler srScheduler) {
-        this.dps = Preconditions.checkNotNull(dps);
-        this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
-        this.srScheduler = Preconditions.checkNotNull(srScheduler);
-        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);
-        flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this);
-        flowStats = new FlowStatsTracker(flowStatsService, this, flowTableStats);
-        groupDescStats = new GroupDescStatsTracker(groupStatsService, this);
-        groupStats = new GroupStatsTracker(groupStatsService, this);
-        meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this);
-        meterStats = new MeterStatsTracker(meterStatsService, this);
-        nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this);
-        queueStats = new QueueStatsTracker(queueStatsService, this);
-    }
-
-    public NodeKey getTargetNodeKey() {
-        return targetNodeKey;
-    }
-
-    @Override
-    public InstanceIdentifier<Node> getNodeIdentifier() {
-        return targetNodeIdentifier;
-    }
-
-    @Override
-    public NodeRef getNodeRef() {
-        return targetNodeRef;
-    }
-
-    @Override
-    public DataModificationTransaction startDataModification() {
-        DataModificationTransaction dmt = dps.beginTransaction();
-        dmt.registerListener(this.srScheduler);
-        return dmt;
-    }
-
-    public synchronized void updateGroupDescStats(TransactionAware transaction, List<GroupDescStats> list) {
-        if (msgManager.isExpectedTransaction(transaction)) {
-            groupDescStats.updateStats(list);
-        }
-    }
-
-    public synchronized void updateGroupStats(TransactionAware transaction, List<GroupStats> list) {
-        if (msgManager.isExpectedTransaction(transaction)) {
-            groupStats.updateStats(list);
-        }
-    }
-
-    public synchronized void updateMeterConfigStats(TransactionAware transaction, List<MeterConfigStats> list) {
-        if (msgManager.isExpectedTransaction(transaction)) {
-            meterConfigStats.updateStats(list);
-        }
-    }
-
-    public synchronized void updateMeterStats(TransactionAware transaction, List<MeterStats> list) {
-        if (msgManager.isExpectedTransaction(transaction)) {
-            meterStats.updateStats(list);
-        }
-    }
-
-    public synchronized void updateQueueStats(TransactionAware transaction, List<QueueIdAndStatisticsMap> list) {
-        if (msgManager.isExpectedTransaction(transaction)) {
-            queueStats.updateStats(list);
-        }
-    }
-
-    public synchronized void updateFlowTableStats(TransactionAware transaction, List<FlowTableAndStatisticsMap> list) {
-        if (msgManager.isExpectedTransaction(transaction)) {
-            flowTableStats.updateStats(list);
-        }
-    }
-
-    public synchronized void updateNodeConnectorStats(TransactionAware transaction, List<NodeConnectorStatisticsAndPortNumberMap> list) {
-        if (msgManager.isExpectedTransaction(transaction)) {
-            nodeConnectorStats.updateStats(list);
-        }
-    }
-
-    public synchronized void updateAggregateFlowStats(TransactionAware transaction, AggregateFlowStatistics flowStats) {
-        final Short tableId = msgManager.isExpectedTableTransaction(transaction);
-        if (tableId != null) {
-            final DataModificationTransaction trans = this.startDataModification();
-            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, List<FlowAndStatisticsMapList> list) {
-        if (msgManager.isExpectedTransaction(transaction)) {
-            flowStats.updateStats(list);
-        }
-    }
-
-    public synchronized void updateGroupFeatures(GroupFeatures notification) {
-        final DataModificationTransaction trans = this.startDataModification();
-
-        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 = this.startDataModification();
-
-        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 = this.startDataModification();
-
-        flowStats.cleanup(trans);
-        groupDescStats.cleanup(trans);
-        groupStats.cleanup(trans);
-        meterConfigStats.cleanup(trans);
-        meterStats.cleanup(trans);
-        nodeConnectorStats.cleanup(trans);
-        queueStats.cleanup(trans);
-        msgManager.cleanStaleTransactionIds();
-
-        trans.commit();
-    }
-
-    public synchronized void requestPeriodicStatistics() {
-        logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
-
-        this.srScheduler.addRequestToSchedulerQueue(flowTableStats);
-
-        this.srScheduler.addRequestToSchedulerQueue(flowStats);
-
-        this.srScheduler.addRequestToSchedulerQueue(nodeConnectorStats);
-
-        this.srScheduler.addRequestToSchedulerQueue(groupStats);
-
-        this.srScheduler.addRequestToSchedulerQueue(groupDescStats);
-
-        this.srScheduler.addRequestToSchedulerQueue(meterStats);
-
-        this.srScheduler.addRequestToSchedulerQueue(meterConfigStats);
-
-        this.srScheduler.addRequestToSchedulerQueue(queueStats);
-    }
-
-    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();
-
-        //Clean up queued statistics request from scheduler queue
-        srScheduler.removeRequestsFromSchedulerQueue(this.getNodeRef());
-
-        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);
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java
deleted file mode 100644 (file)
index d1f2529..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-
-final class QueueStatsEntry {
-    private final NodeConnectorId nodeConnectorId;
-    private final QueueId queueId;
-    public QueueStatsEntry(NodeConnectorId ncId, QueueId queueId){
-        this.nodeConnectorId = ncId;
-        this.queueId = queueId;
-    }
-    public NodeConnectorId getNodeConnectorId() {
-        return nodeConnectorId;
-    }
-    public QueueId getQueueId() {
-        return queueId;
-    }
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode());
-        result = prime * result + ((queueId == null) ? 0 : queueId.hashCode());
-        return result;
-    }
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (!(obj instanceof QueueStatsEntry)) {
-            return false;
-        }
-        QueueStatsEntry other = (QueueStatsEntry) obj;
-        if (nodeConnectorId == null) {
-            if (other.nodeConnectorId != null) {
-                return false;
-            }
-        } else if (!nodeConnectorId.equals(other.nodeConnectorId)) {
-            return false;
-        }
-        if (queueId == null) {
-            if (other.queueId != null) {
-                return false;
-            }
-        } else if (!queueId.equals(other.queueId)) {
-            return false;
-        }
-        return true;
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java
deleted file mode 100644 (file)
index 4a58970..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.util.Map.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) {
-        super(context);
-        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;
-    }
-
-    @Override
-    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 = queue
-                        .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class);
-                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);
-    }
-
-    @Override
-    protected QueueStatsEntry createInvariantKey(QueueStatsEntry item) {
-        // No invariant data exist in the group description stats.
-        return item;
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatListeningCommiter.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatListeningCommiter.java
new file mode 100644 (file)
index 0000000..7589c72
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * 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.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager
+ *
+ * StatListeningCommiter
+ * Definition Interface for {@link DataChangeListener} implementer class rule.
+ * Interface represent a contract between Config/DataStore changes and
+ * Operational/DataStore commits. All Operational/DataStore commit have
+ * to by represent as RPC Device response Notification processing. So
+ * Operational/DS could contains only real mirror of OF Device
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Aug 27, 2014
+ */
+public interface StatListeningCommiter<T extends DataObject, N extends NotificationListener> extends DataChangeListener, StatNotifyCommiter<N> {
+
+
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatNodeRegistration.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatNodeRegistration.java
new file mode 100644 (file)
index 0000000..80a15a3
--- /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.controller.md.statistics.manager;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SwitchFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager.impl
+ *
+ * StatNodeRegistration
+ * Class represents {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode}
+ * {@link org.opendaylight.controller.md.sal.binding.api.DataChangeListener} in Operational/DataStore for ADD / REMOVE
+ * actions which are represented connect / disconnect OF actions. Connect functionality are expecting
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Sep 5, 2014
+ */
+public interface StatNodeRegistration extends OpendaylightInventoryListener, AutoCloseable {
+
+    /**
+     * Method contains {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode} registration to {@link StatisticsManager}
+     * for permanently collecting statistics by {@link StatPermCollector} and
+     * as a prevention to use a validation check to the Operational/DS for identify
+     * connected {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode}.
+     *
+     * @param InstanceIdentifier<SwitchFeatures> keyIdent
+     * @param FlowCapableNode data
+     * @param InstanceIdentifier<Node> nodeIdent
+     */
+    void connectFlowCapableNode(InstanceIdentifier<SwitchFeatures> keyIdent,
+            SwitchFeatures data, InstanceIdentifier<Node> nodeIdent);
+
+    /**
+     * Method cut {@link Node} registration for {@link StatPermCollector}
+     *
+     * @param InstanceIdentifier<Node> keyIdent
+     */
+    void disconnectFlowCapableNode(InstanceIdentifier<Node> keyIdent);
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatNotifyCommiter.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatNotifyCommiter.java
new file mode 100644 (file)
index 0000000..0392e47
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * 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.yangtools.yang.binding.NotificationListener;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager
+ *
+ * StatNotifyCommiter
+ * Definition Interface for notification implementer class rule
+ * Interface represent a contract between RPC Device Notification
+ * and Operational/DataStore commits.
+ *
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Aug 28, 2014
+ */
+public interface StatNotifyCommiter<N extends NotificationListener> extends AutoCloseable, NotificationListener {
+
+
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatPermCollector.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatPermCollector.java
new file mode 100644 (file)
index 0000000..9116e66
--- /dev/null
@@ -0,0 +1,115 @@
+/**
+ * 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.List;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager
+ *
+ * StatPermCollector
+ * Class implement {@link Runnable} and inside is running statistic collecting
+ * process DataObject statistics by DataObject statistics for every {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode}.
+ * Every statistics wait to finish previous statistics. Only if all statistics finish,
+ * next {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode}
+ * Statistics should be collecting. We are able to set minimal time for start next round cross all Network,
+ * but all depends on network possibility.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Aug 28, 2014
+ */
+public interface StatPermCollector extends Runnable, AutoCloseable {
+
+    /**
+     * StatCapType
+     * Enum class refers ofp_statistics capabilities fields from OF Switch
+     * capabilities specification which have to come as a post HandShake
+     * information from OF Switch and Inventory Manager adds all to the
+     * Operational/DS.
+     * If the capabilities are not add (for any reason) NodeRegistrator
+     * adds all StatCapTypes for the {@link Node}.
+     */
+    public enum StatCapabTypes {
+        /**
+         * OFPC_FLOW_STATS
+         */
+        FLOW_STATS,
+        /**
+         * OFPC_TABLE_STATS
+         */
+        TABLE_STATS,
+        /**
+         * OFPC_PORT_STATS
+         */
+        PORT_STATS,
+        /**
+         * OFPC_GROUP_STATS
+         */
+        GROUP_STATS,
+        /**
+         * OFPC_QUEUE_STATS
+         */
+        QUEUE_STATS,
+        /**
+         * Meter statistics has no support from OF Switch capabilities
+         * so we have to try get statistics for it and wait for response
+         * Error or response package with results.
+         */
+        METER_STATS
+    }
+
+    /**
+     * Add new connected node for permanent statistics collecting process
+     *
+     * @param flowNode
+     * @param statTypes
+     * @param nrOfSwitchTables
+     * @return true/false if the {@link Node} added successful
+     */
+    boolean connectedNodeRegistration(InstanceIdentifier<Node> nodeIdent,
+            List<StatCapabTypes> statTypes, Short nrOfSwitchTables);
+
+    /**
+     * All disconnected Nodes need be removed from stat list Nodes
+     * @param flowNode
+     * @return true/false if the {@link Node} removed successful
+     */
+    boolean disconnectedNodeUnregistration(InstanceIdentifier<Node> nodeIdent);
+
+    /**
+     * Method return true only and only if {@link StatPermCollector} contain
+     * valid node registration in its internal {@link Node} map.
+     * Otherwise return false.
+     *
+     * @param InstanceIdentifier<FlowCapableNode> flowNode
+     * @return
+     */
+    boolean isProvidedFlowNodeActive(InstanceIdentifier<Node> nodeIdent);
+
+    /**
+     * Object notification for continue statistics collecting process.
+     * It is call from collecting allStatistics methods as a future result for
+     * Operational/DS statistic store call (does not matter in the outcome).
+     */
+    void collectNextStatistics();
+
+    /**
+     * Method returns true if collector has registered some active nodes
+     * otherwise return false.
+     *
+     * @return
+     */
+    boolean hasActiveNodes();
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatRpcMsgManager.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatRpcMsgManager.java
new file mode 100644 (file)
index 0000000..0576c2a
--- /dev/null
@@ -0,0 +1,191 @@
+/**
+ * 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.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+
+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 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.base.Optional;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager
+ *
+ * StatRpcMsgManager
+ * It represent access point for Device statistics RPC services which are
+ * filtered for needed methods only and they are wrapped in simply way.
+ * Many statistics responses are Multipart messages, so StatRpcMsgManager
+ * provide a functionality to add all multipart msg and provides back whole
+ * stack to listener when listener catch the last Multipart msg.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Aug 29, 2014
+ */
+public interface StatRpcMsgManager extends Runnable, AutoCloseable {
+
+    interface RpcJobsQueue extends Callable<Void> {}
+
+    /**
+     * Transaction container is definition for Multipart transaction
+     * join container for all Multipart msg with same TransactionId
+     * Input {@link DataObject} is a possible light-weight DataObject
+     * which is used for identification (e.g. Flow-> Priority,Match,Cookie,FlowId)
+     *
+     * @param <T> extends TransactionAware -
+     */
+    interface TransactionCacheContainer<T extends TransactionAware> {
+
+        void addNotif(T notification);
+
+        TransactionId getId();
+
+        NodeId getNodeId();
+
+        Optional<? extends DataObject> getConfInput();
+
+        List<T> getNotifications();
+    }
+
+    /**
+     * Method is used for check a transaction registration
+     * for multipart cache holder
+     *
+     * @param TransactionId id
+     * @return true if the transaction has been correctly registered
+     */
+    Future<Boolean> isExpectedStatistics(TransactionId id, NodeId nodeId);
+
+    /**
+     * Method converts {@link java.util.concurrent.Future} object to listenenable future which
+     * is registered for Multipart Notification Statistics Collecting processing.
+     *
+     * @param future - result every Device RPC call
+     */
+    <T extends TransactionAware, D extends DataObject> void registrationRpcFutureCallBack(Future<RpcResult<T>> future, D inputObj, NodeRef ref);
+
+    /**
+     * Method adds Notification which is marked as Multipart to the transaction cash
+     * to wait for the last one.
+     *
+     * @param notification
+     */
+    <T extends TransactionAware> void addNotification(T notification, NodeId nodeId);
+
+    /**
+     * The last Multipart should inform code about possibility to take all previous
+     * messages for next processing. The method take all msg and possible input object
+     * and build all to TransactionCacheContainer Object to return. This process clean
+     * all instances in Cache.
+     *
+     * @param TransactionId id
+     * @return TransactionCacheContainer
+     */
+    Future<Optional<TransactionCacheContainer<?>>> getTransactionCacheContainer(TransactionId id, NodeId nodeId);
+
+    /**
+     * Method wraps OpendaylightGroupStatisticsService.getAllGroupStatistics
+     * and registers to Transaction Cache
+     *
+     * @param NodeRef nodeRef
+     */
+    void getAllGroupsStat(NodeRef nodeRef);
+
+    /**
+     * Method wraps OpendaylightGroupStatisticsService.getGroupDescription
+     * and registers to Transaction Cache
+     *
+     * @param NodeRef nodeRef
+     */
+    void getAllGroupsConfStats(NodeRef nodeRef);
+
+    /**
+     * Method wraps OpendaylightMeterStatisticsService.getGroupFeatures
+     * and registers to Transaction Cache
+     *
+     * @param NodeRef nodeRef
+     */
+    void getGroupFeaturesStat(NodeRef nodeRef);
+
+    /**
+     * Method wraps OpendaylightMeterStatisticsService.getAllMeterStatistics
+     * and registers to Transaction Cache
+     *
+     * @param NodeRef nodeRef
+     */
+    void getAllMetersStat(NodeRef nodeRef);
+
+    /**
+     * Method wraps OpendaylightMeterStatisticsService.getAllMeterConfigStatistics
+     * and registers to Transaction Cache
+     *
+     * @param NodeRef nodeRef
+     */
+    void getAllMeterConfigStat(NodeRef nodeRef);
+
+    /**
+     * Method wraps OpendaylightMeterStatisticsService.getMeterFeatures
+     * and registers to Transaction Cache
+     *
+     * @param NodeRef nodeRef
+     */
+    void getMeterFeaturesStat(NodeRef nodeRef);
+
+    /**
+     * Method wraps OpendaylightFlowStatisticsService.getAllFlowsStatisticsFromAllFlowTables
+     * and registers to Transaction Cache
+     *
+     * @param NodeRef nodeRef
+     */
+    void getAllFlowsStat(NodeRef nodeRef);
+
+    /**
+     * Method wraps OpendaylightFlowStatisticsService.getAggregateFlowStatisticsFromFlowTableForAllFlows
+     * and registers to Transaction Cache
+     *
+     * @param NodeRef nodeRef
+     * @param TableId tableId
+     */
+    void getAggregateFlowStat(NodeRef nodeRef, TableId tableId);
+
+    /**
+     * Method wraps OpendaylightPortStatisticsService.getAllNodeConnectorsStatistics
+     * and registers to Transaction Cache
+     *
+     * @param NodeRef nodeRef
+     */
+    void getAllPortsStat(NodeRef nodeRef);
+
+    /**
+     * Method wraps OpendaylightFlowTableStatisticsService.getFlowTablesStatistics
+     * and registers to Transaction Cache
+     *
+     * @param NodeRef nodeRef
+     */
+    void getAllTablesStat(NodeRef nodeRef);
+
+    /**
+     * Method wraps OpendaylightQueueStatisticsService.getAllQueuesStatisticsFromAllPorts
+     * and registers to Transaction Cache
+     *
+     * @param NodeRef nodeRef
+     */
+    void getAllQueueStat(NodeRef nodeRef);
+
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java
deleted file mode 100644 (file)
index a06f7ef..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import 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.getMeterConfigStats());
-        }
-    }
-
-    @Override
-    public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) {
-        final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
-        if (handler != null) {
-            handler.updateMeterStats(notification, notification.getMeterStats());
-        }
-    }
-
-    @Override
-    public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) {
-        final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId());
-        if (handler != null) {
-            handler.updateGroupDescStats(notification, notification.getGroupDescStats());
-        }
-    }
-
-    @Override
-    public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) {
-        final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId());
-        if (handler != null) {
-            handler.updateGroupStats(notification, 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.getFlowAndStatisticsMapList());
-        }
-    }
-
-    @Override
-    public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
-        final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
-        if (handler != null) {
-            handler.updateAggregateFlowStats(notification, notification);
-        }
-    }
-
-    @Override
-    public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
-        final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
-        if (handler != null) {
-            handler.updateNodeConnectorStats(notification, notification.getNodeConnectorStatisticsAndPortNumberMap());
-        }
-    }
-
-    @Override
-    public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
-        final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
-        if (handler != null) {
-            handler.updateFlowTableStats(notification, notification.getFlowTableAndStatisticsMap());
-        }
-    }
-
-    @Override
-    public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) {
-        final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
-        if (handler != null) {
-            handler.updateQueueStats(notification, notification.getQueueIdAndStatisticsMap());
-        }
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManager.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManager.java
new file mode 100644 (file)
index 0000000..b53c54e
--- /dev/null
@@ -0,0 +1,179 @@
+/**
+ * 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.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.statistics.manager.StatPermCollector.StatCapabTypes;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
+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.OpendaylightFlowStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
+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.OpendaylightGroupStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener;
+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.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager
+ *
+ * StatisticsManager
+ * It represent a central point for whole module. Implementation
+ * StatisticsManager registers all Operation/DS {@link StatNotifyCommiter} and
+ * Config/DS {@StatListeningCommiter}, as well as {@link StatPermCollector}
+ * for statistic collecting and {@link StatRpcMsgManager} as Device RPCs provider.
+ * In next, StatisticsManager provides all DS contact Transaction services.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Aug 27, 2014
+ */
+public interface StatisticsManager extends AutoCloseable, TransactionChainListener {
+
+    /**
+     * StatDataStoreOperation
+     * Interface represent functionality to submit changes to DataStore.
+     * Internal {@link TransactionChainListener} joining all DS commits
+     * to Set of chained changes for prevent often DataStore touches.
+     */
+    public interface StatDataStoreOperation {
+
+        /**
+         * Apply all read / write (put|merge) operation
+         * for DataStore
+         * @param {@link ReadWriteTransaction} tx
+         */
+        void applyOperation(ReadWriteTransaction tx);
+
+    }
+
+    /**
+     * Method starts whole StatisticManager functionality
+     *
+     * @param {@link NotificationProviderService} notifService
+     * @param {@link RpcConsumerRegistry} rpcRegistry
+     * @param minReqNetMonitInt
+     */
+    void start(final NotificationProviderService notifService,
+            final RpcConsumerRegistry rpcRegistry, final long minReqNetMonitInt);
+
+    /**
+     * Method provides read/write DataStore functionality cross applyOperation
+     * defined in {@link StatDataStoreOperation}
+     *
+     * @param inventoryOper - operation for DataStore
+     */
+    void enqueue(final StatDataStoreOperation inventoryOper);
+
+    /**
+     * Method wraps {@link StatisticCollector}.isProvidedFlowNodeActive method
+     * to provide parallel statCollection process for Set of Nodes. So it has to
+     * identify correct Node Set by NodeIdentifier
+     *
+     * @param nodeIdent
+     */
+     boolean isProvidedFlowNodeActive(InstanceIdentifier<Node> nodeIdent);
+
+     /**
+      * Method wraps {@link StatPermCollector}.collectNextStatistics to provide
+      * parallel statCollection process for Set of Nodes. So it has to
+      * identify correct Node Set by NodeIdentifier.
+      *
+      * @param nodeIdent
+      */
+     void collectNextStatistics(InstanceIdentifier<Node> nodeIdent);
+
+     /**
+      * Method wraps {@link StatPermCollector}.connectedNodeRegistration to provide
+      * parallel statCollection process for Set of Nodes. So it has to
+      * connect node to new or not full Node statCollector Set.
+      *
+      * @param nodeIdent
+      * @param statTypes
+      * @param nrOfSwitchTables
+      */
+     void connectedNodeRegistration(InstanceIdentifier<Node> nodeIdent,
+             List<StatCapabTypes> statTypes, Short nrOfSwitchTables);
+
+     /**
+      * Method wraps {@link StatPermCollector}.disconnectedNodeUnregistration to provide
+      * parallel statCollection process for Set of Nodes. So it has to identify
+      * correct collector for disconnect node.
+      *
+      * @param nodeIdent
+      */
+     void disconnectedNodeUnregistration(InstanceIdentifier<Node> nodeIdent);
+
+    /**
+     * Method provides access to Device RPC methods by wrapped
+     * internal method. In next {@link StatRpcMsgManager} is registered all
+     * Multipart device msg response and joining all to be able run all
+     * collected statistics in one time (easy identification Data for delete)
+     *
+     * @return {@link StatRpcMsgManager}
+     */
+    StatRpcMsgManager getRpcMsgManager();
+
+    /**
+     * Define Method : {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode}
+     * Operational/DS data change listener -> impl. target -> register FlowCapableNode to Statistic Collecting process
+     * @return {@link StatNodeRegistration}
+     */
+    StatNodeRegistration getNodeRegistrator();
+
+    /**
+     * Define Method : Flow Config/DS data change listener -> impl. target ->
+     * -> make pair between Config/DS FlowId and Device Flow response Hash
+     * @return
+     */
+    StatListeningCommiter<Flow, OpendaylightFlowStatisticsListener> getFlowListenComit();
+
+    /**
+     * Define Method : Meter Config/DS data change listener and Operation/DS notify commit
+     * functionality
+     * @return
+     */
+    StatListeningCommiter<Meter, OpendaylightMeterStatisticsListener> getMeterListenCommit();
+
+    /**
+     * Define Method : Group Config/DS data change listener and Operation/DS notify commit
+     * functionality
+     * @return
+     */
+    StatListeningCommiter<Group, OpendaylightGroupStatisticsListener> getGroupListenCommit();
+
+    /**
+     * Define Method : Queue Config/DS change listener and Operation/DS notify commit functionality
+     * @return
+     */
+    StatListeningCommiter<Queue, OpendaylightQueueStatisticsListener> getQueueNotifyCommit();
+
+    /**
+     * Define Method : Table Operation/DS notify commit functionality
+     * @return
+     */
+    StatNotifyCommiter<OpendaylightFlowTableStatisticsListener> getTableNotifCommit();
+
+    /**
+     * Define Method : Port Operation/DS notify commit functionality
+     * @return
+     */
+    StatNotifyCommiter<OpendaylightPortStatisticsListener> getPortNotifyCommit();
+
+}
+
index 5bcbef1..912a6ed 100644 (file)
@@ -8,29 +8,66 @@
 
 package org.opendaylight.controller.md.statistics.manager;
 
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.statistics.manager.impl.StatisticsManagerImpl;
 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.DataProviderService;
 import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Statistics Manager Activator
+ *
+ * OSGi bundle activator
+ *
+ */
 public class StatisticsManagerActivator extends AbstractBindingAwareProvider {
-    private StatisticsProvider statsProvider;
+
+    private final static Logger LOG = LoggerFactory.getLogger(StatisticsManagerActivator.class);
+
+    /* TODO move it to ConfigSubsystem */
+    private static final long DEFAULT_MIN_REQUEST_NET_MONITOR_INTERVAL = 3000L;
+    private static final int MAX_NODES_FOR_COLLECTOR = 8;
+
+    private StatisticsManager statsProvider;
 
     @Override
-    public void onSessionInitiated(ProviderContext session) {
-        final DataProviderService dps = session.getSALService(DataProviderService.class);
-        final NotificationProviderService nps = session.getSALService(NotificationProviderService.class);
+    public void onSessionInitiated(final ProviderContext session) {
+        LOG.info("StatisticsManagerActivator initialization.");
+        try {
+            final DataBroker dataBroker = session.getSALService(DataBroker.class);
+            final NotificationProviderService notifService =
+                    session.getSALService(NotificationProviderService.class);
+            statsProvider = new StatisticsManagerImpl(dataBroker, MAX_NODES_FOR_COLLECTOR);
+            statsProvider.start(notifService, session, DEFAULT_MIN_REQUEST_NET_MONITOR_INTERVAL);
+            LOG.info("StatisticsManagerActivator started successfully.");
+        }
+        catch (final Exception e) {
+            LOG.error("Unexpected error by initialization of StatisticsManagerActivator", e);
+            stopImpl(null);
+        }
+    }
 
-        statsProvider = new StatisticsProvider(dps);
-        statsProvider.start(nps, session);
+    @VisibleForTesting
+    StatisticsManager getStatisticManager() {
+        return statsProvider;
     }
 
     @Override
-    protected void stopImpl(BundleContext context) {
+    protected void stopImpl(final BundleContext context) {
         if (statsProvider != null) {
-            statsProvider.close();
+            try {
+                statsProvider.close();
+            }
+            catch (final Exception e) {
+                LOG.error("Unexpected error by stopping StatisticsManagerActivator", e);
+            }
             statsProvider = null;
         }
+        LOG.info("StatisticsManagerActivator stoped.");
     }
 }
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java
deleted file mode 100644 (file)
index 8c9b60e..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.util.Collection;
-import java.util.Timer;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-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.statistics.rev130819.OpendaylightFlowStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.NotificationListener;
-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
- * operational data store.
- *
- * @author avishnoi@in.ibm.com
- *
- */
-public class StatisticsProvider implements AutoCloseable {
-    private static final Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class);
-
-    private final ConcurrentMap<NodeId, NodeStatisticsHandler> handlers = new ConcurrentHashMap<>();
-    private final Timer timer = new Timer("statistics-manager", true);
-    private final DataProviderService dps;
-
-    private OpendaylightGroupStatisticsService groupStatsService;
-
-    private OpendaylightMeterStatisticsService meterStatsService;
-
-    private OpendaylightFlowStatisticsService flowStatsService;
-
-    private OpendaylightPortStatisticsService portStatsService;
-
-    private OpendaylightFlowTableStatisticsService flowTableStatsService;
-
-    private OpendaylightQueueStatisticsService queueStatsService;
-
-    private final StatisticsRequestScheduler srScheduler;
-
-    public StatisticsProvider(final DataProviderService dataService) {
-        this.dps = Preconditions.checkNotNull(dataService);
-        this.srScheduler = new StatisticsRequestScheduler();
-    }
-
-    private final StatisticsListener updateCommiter = new StatisticsListener(StatisticsProvider.this);
-
-    private ListenerRegistration<NotificationListener> listenerRegistration;
-
-    private ListenerRegistration<DataChangeListener> flowCapableTrackerRegistration;
-
-    public void start(final NotificationProviderService nps, final RpcConsumerRegistry rpcRegistry) {
-
-        // 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);
-        this.srScheduler.start();
-
-        // Start receiving notifications
-        this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter);
-
-        // Register for switch connect/disconnect notifications
-        final InstanceIdentifier<FlowCapableNode> fcnId = InstanceIdentifier.builder(Nodes.class)
-                .child(Node.class).augmentation(FlowCapableNode.class).build();
-        spLogger.debug("Registering FlowCapable tracker to {}", fcnId);
-        this.flowCapableTrackerRegistration = dps.registerDataChangeListener(fcnId,
-                new FlowCapableTracker(this, fcnId));
-
-        spLogger.info("Statistics Provider started.");
-    }
-
-    /**
-     * 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;
-    }
-
-    @Override
-    public void close() {
-        try {
-            if (this.listenerRegistration != null) {
-                this.listenerRegistration.close();
-                this.listenerRegistration = null;
-            }
-            if (this.flowCapableTrackerRegistration != null) {
-                this.flowCapableTrackerRegistration.close();
-                this.flowCapableTrackerRegistration = null;
-            }
-            timer.cancel();
-        } catch (Exception e) {
-            spLogger.warn("Failed to stop Statistics Provider completely", e);
-        } finally {
-            spLogger.info("Statistics Provider stopped.");
-        }
-    }
-
-    void startNodeHandlers(final Collection<NodeKey> addedNodes) {
-        for (NodeKey key : addedNodes) {
-            if (handlers.containsKey(key.getId())) {
-                spLogger.warn("Attempted to start already-existing handler for {}, very strange", key.getId());
-                continue;
-            }
-
-            final NodeStatisticsHandler h = new NodeStatisticsHandler(dps, key,
-                    flowStatsService, flowTableStatsService, groupStatsService,
-                    meterStatsService, portStatsService, queueStatsService,srScheduler);
-            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());
-            }
-        }
-    }
-
-    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());
-            }
-        }
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java
deleted file mode 100644 (file)
index 29a27e2..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.TimeUnit;
-
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction.DataTransactionListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Main responsibility of the class is to check the MD-SAL data store read/write
- * transaction accumulation level and send statistics request if number of pending
- * read/write transactions are zero.
- * @author avishnoi@in.ibm.com
- *
- */
-@SuppressWarnings("rawtypes")
-public class StatisticsRequestScheduler implements DataTransactionListener {
-
-    private static final Logger srsLogger = LoggerFactory.getLogger(StatisticsRequestScheduler.class);
-    private final Timer timer = new Timer("request-monitor", true);
-
-    // We need ordered retrieval, and O(1) contains operation
-    private final Map<AbstractStatsTracker,Integer> requestQueue =
-            Collections.synchronizedMap(new LinkedHashMap<AbstractStatsTracker,Integer>());
-
-    private Long PendingTransactions;
-
-    private long lastRequestTime = System.nanoTime();
-
-    private static final long REQUEST_MONITOR_INTERVAL = 1000;
-
-    private final TimerTask task = new TimerTask() {
-        @Override
-        public void run() {
-            try{
-                long now = System.nanoTime();
-                if(now > lastRequestTime+TimeUnit.MILLISECONDS.toNanos(REQUEST_MONITOR_INTERVAL)){
-                    requestStatistics();
-                }
-            }catch (IllegalArgumentException | IllegalStateException | NullPointerException e){
-                srsLogger.warn("Exception occured while sending statistics request : {}",e);
-            }
-        }
-    };
-
-    public StatisticsRequestScheduler(){
-        PendingTransactions = (long) 0;
-    }
-
-    public void addRequestToSchedulerQueue(AbstractStatsTracker statsRequest){
-        requestQueue.put(statsRequest, null);
-    }
-
-    public void removeRequestsFromSchedulerQueue(NodeRef node){
-        AbstractStatsTracker stats = null;
-        synchronized(requestQueue){
-            Iterator<Map.Entry<AbstractStatsTracker, Integer>> nodesItr = requestQueue.entrySet().iterator();
-            while(nodesItr.hasNext()){
-                stats = nodesItr.next().getKey();
-                if(stats.getNodeRef().equals(node)){
-                    nodesItr.remove();
-                }
-            }
-        }
-
-    }
-    public AbstractStatsTracker getNextRequestFromSchedulerQueue(){
-        //Remove first element
-        AbstractStatsTracker stats = null;
-        synchronized(requestQueue){
-            Iterator<Map.Entry<AbstractStatsTracker, Integer>> nodesItr = requestQueue.entrySet().iterator();
-            if(nodesItr.hasNext()){
-                stats = nodesItr.next().getKey();
-                srsLogger.debug("{} chosen up for execution",stats.getNodeRef());
-                nodesItr.remove();
-                return stats;
-            }
-        }
-        return stats;
-    }
-
-    private void requestStatistics(){
-        AbstractStatsTracker stats = this.getNextRequestFromSchedulerQueue();
-        sendStatsRequest(stats);
-    }
-    @Override
-    public void onStatusUpdated(DataModificationTransaction transaction, TransactionStatus status) {
-
-        AbstractStatsTracker stats = null;
-        synchronized(PendingTransactions){
-            switch(status){
-            case SUBMITED:
-                this.PendingTransactions++;
-                break;
-            case COMMITED:
-            case FAILED:
-                this.PendingTransactions--;
-                if(PendingTransactions == 0){
-                    lastRequestTime = System.nanoTime();
-                    stats = this.getNextRequestFromSchedulerQueue();
-                }
-                srsLogger.debug("Pending MD-SAL transactions : {} & Scheduler queue size : {}",this.PendingTransactions,this.requestQueue.size());
-                break;
-            default:
-                break;
-            }
-        }
-        sendStatsRequest(stats);
-    }
-
-    private void sendStatsRequest(AbstractStatsTracker stats){
-        if(stats != null){
-            try{
-                stats.request();
-                stats.increaseRequestCounter();
-            }catch(Exception e){
-                srsLogger.warn("Statistics request was not sent successfully. Reason : {}",e.getMessage());
-            }
-        }
-    }
-    public void start(){
-        timer.schedule(task, 0, REQUEST_MONITOR_INTERVAL);
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatAbstractListenCommit.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatAbstractListenCommit.java
new file mode 100644 (file)
index 0000000..6ebf944
--- /dev/null
@@ -0,0 +1,134 @@
+/**
+ * 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.impl;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+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.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.statistics.manager.StatListeningCommiter;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+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.binding.NotificationListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager.impl
+ *
+ * StatAbstractListeneningCommiter
+ * Class is abstract implementation for all Configuration/DataStore DataChange
+ * listenable DataObjects like flows, groups, meters. It is a holder for common
+ * functionality needed by construction/destruction class and for DataChange
+ * event processing.
+ *
+ */
+public abstract class StatAbstractListenCommit<T extends DataObject, N extends NotificationListener>
+                                            extends StatAbstractNotifyCommit<N> implements StatListeningCommiter<T,N> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(StatAbstractListenCommit.class);
+
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+    protected final Map<InstanceIdentifier<Node>, Map<InstanceIdentifier<T>, Integer>> mapNodesForDelete = new ConcurrentHashMap<>();
+
+    private final Class<T> clazz;
+
+    private final DataBroker dataBroker;
+
+    private volatile ReadOnlyTransaction currentReadTx;
+
+    /* Constructor has to make a registration */
+    public StatAbstractListenCommit(final StatisticsManager manager, final DataBroker db,
+            final NotificationProviderService nps, final Class<T> clazz) {
+        super(manager,nps);
+        this.clazz = Preconditions.checkNotNull(clazz, "Referenced Class can not be null");
+        Preconditions.checkArgument(db != null, "DataBroker can not be null!");
+        listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                getWildCardedRegistrationPath(), this, DataChangeScope.BASE);
+        this.dataBroker = db;
+    }
+
+    /**
+     * Method returns WildCarded Path which is used for registration as a listening path changes in
+     * {@link org.opendaylight.controller.md.sal.binding.api.DataChangeListener}
+     * @return
+     */
+    protected abstract InstanceIdentifier<T> getWildCardedRegistrationPath();
+
+    @Override
+    public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
+        Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!");
+        /*
+         * If we have opened read transaction for configuraiton data store,
+         * we will close and null it.
+         *
+         * Latest read transaction will be allocated on another read using readLatestConfiguration
+         */
+        if(currentReadTx != null) {
+            final ReadOnlyTransaction previous = currentReadTx;
+            currentReadTx = null;
+            previous.close();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected void removeData(final InstanceIdentifier<?> key, final Integer value) {
+        if (clazz.equals(key.getTargetType())) {
+            final InstanceIdentifier<Node> nodeIdent = key.firstIdentifierOf(Node.class);
+            Map<InstanceIdentifier<T>, Integer> map = null;
+            if (mapNodesForDelete.containsKey(nodeIdent)) {
+                map = mapNodesForDelete.get(nodeIdent);
+            }
+            if (map == null) {
+                map = new ConcurrentHashMap<>();
+                mapNodesForDelete.put(nodeIdent, map);
+            }
+            map.put((InstanceIdentifier<T>) key, value);
+        }
+    }
+
+    @Override
+    public void close() {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error by stop {} DataChange StatListeningCommiter.", clazz.getSimpleName(), e);
+            }
+            listenerRegistration = null;
+        }
+    }
+
+    protected final <K extends DataObject> Optional<K> readLatestConfiguration(final InstanceIdentifier<K> path) {
+        if(currentReadTx == null) {
+             currentReadTx = dataBroker.newReadOnlyTransaction();
+        }
+        try {
+            return currentReadTx.read(LogicalDatastoreType.CONFIGURATION, path).checkedGet();
+        } catch (final ReadFailedException e) {
+            return Optional.absent();
+        }
+    }
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatAbstractNotifyCommit.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatAbstractNotifyCommit.java
new file mode 100644 (file)
index 0000000..08871e9
--- /dev/null
@@ -0,0 +1,134 @@
+/**
+ * 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.impl;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opendaylight.controller.md.statistics.manager.StatNotifyCommiter;
+import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+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.opendaylight.yangtools.yang.binding.NotificationListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager.impl
+ *
+ * StatAbstratNotifiCommiter
+ * Class is abstract implementation for all no Configuration/DataStore DataObjects
+ * and represent common functionality for all DataObject Statistics Commiters.
+ * Class defines contract between DataObject and relevant Statistics NotificationListener.
+ *
+ */
+public abstract class StatAbstractNotifyCommit<N extends NotificationListener> implements StatNotifyCommiter<N> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(StatAbstractNotifyCommit.class);
+
+    protected final StatisticsManager manager;
+    private ListenerRegistration<NotificationListener> notifyListenerRegistration;
+
+    public StatAbstractNotifyCommit(final StatisticsManager manager,
+            final NotificationProviderService nps) {
+        Preconditions.checkArgument(nps != null, "NotificationProviderService can not be null!");
+        this.manager = Preconditions.checkNotNull(manager, "StatisticManager can not be null!");
+        notifyListenerRegistration = nps.registerNotificationListener(getStatNotificationListener());
+    }
+
+    @Override
+    public void close() {
+        if (notifyListenerRegistration != null) {
+            try {
+                notifyListenerRegistration.close();
+            }
+            catch (final Exception e) {
+                LOG.error("Error by stop {} StatNotificationListener.", this.getClass().getSimpleName());
+            }
+            notifyListenerRegistration = null;
+        }
+    }
+
+    /**
+     * Method returns Statistics Notification Listener for relevant DataObject implementation,
+     * which is declared for {@link StatNotifyCommiter} interface.
+     *
+     * @return
+     */
+    protected abstract N getStatNotificationListener();
+
+    /**
+     * PreConfigurationCheck - Node identified by input InstanceIdentifier<Node>
+     * has to be registered in {@link org.opendaylight.controller.md.statistics.manager.StatPermCollector}
+     *
+     * @param InstanceIdentifier<Node> nodeIdent
+     */
+    protected boolean preConfigurationCheck(final InstanceIdentifier<Node> nodeIdent) {
+        Preconditions.checkNotNull(nodeIdent, "FlowCapableNode ident can not be null!");
+        return manager.isProvidedFlowNodeActive(nodeIdent);
+    }
+
+    protected void notifyToCollectNextStatistics(final InstanceIdentifier<Node> nodeIdent) {
+        Preconditions.checkNotNull(nodeIdent, "FlowCapableNode ident can not be null!");
+        manager.collectNextStatistics(nodeIdent);
+    }
+
+    /**
+     * Wrapping Future object call for {@link org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager}
+     * getTransactionCacheContainer with 10sec TimeOut.
+     * Method has returned {@link Optional} which could contains a {@link TransactionCacheContainer}
+     *
+     * @param TransactionId transId
+     * @param NodeId nodeId
+     * @return
+     */
+    protected Optional<TransactionCacheContainer<?>> getTransactionCacheContainer(final TransactionId transId, final NodeId nodeId) {
+        Optional<TransactionCacheContainer<?>> txContainer;
+        try {
+            txContainer = manager.getRpcMsgManager().getTransactionCacheContainer(transId, nodeId).get(10, TimeUnit.SECONDS);
+        }
+        catch (InterruptedException | ExecutionException | TimeoutException e) {
+            LOG.warn("Get TransactionCacheContainer fail!", e);
+            txContainer = Optional.absent();
+        }
+        return txContainer;
+    }
+
+    /**
+     * Wrapping Future object call to {@link org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager}
+     * isExpectedStatistics with 10sec TimeOut.
+     * Method has checked registration for provided {@link TransactionId} and {@link NodeId}
+     *
+     * @param TransactionId transId - Transaction identification
+     * @param NodeId nodeId - Node identification
+     * @return boolean
+     */
+    protected boolean isExpectedStatistics(final TransactionId transId, final NodeId nodeId) {
+        Boolean isExpectedStat = Boolean.FALSE;
+        try {
+            isExpectedStat = manager.getRpcMsgManager().isExpectedStatistics(transId, nodeId).get(10, TimeUnit.SECONDS);
+        }
+        catch (InterruptedException | ExecutionException | TimeoutException e) {
+            LOG.warn("Check Transaction registraion {} fail!", transId, e);
+            return false;
+        }
+        return isExpectedStat.booleanValue();
+    }
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitFlow.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitFlow.java
new file mode 100644 (file)
index 0000000..c5aefcb
--- /dev/null
@@ -0,0 +1,451 @@
+/**
+ * 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.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation;
+import org.opendaylight.controller.md.statistics.manager.impl.helper.FlowComparator;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowHashIdMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowHashIdMappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowHashIdMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowHashIdMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowHashIdMapKey;
+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.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.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 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.binding.KeyedInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager.impl
+ *
+ * StatListenCommitFlow
+ * Class is a NotifyListener for FlowStatistics and DataChangeListener for Config/DataStore for Flow node.
+ * All expected (registered) FlowStatistics will be builded and commit to Operational/DataStore.
+ * DataChangeEven should call create/delete Flow in Operational/DS create process needs to pair
+ * Device Flow HashCode and FlowId from Config/DS
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class StatListenCommitFlow extends StatAbstractListenCommit<Flow, OpendaylightFlowStatisticsListener>
+                                            implements OpendaylightFlowStatisticsListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(StatListenCommitFlow.class);
+
+    private static final String ALIEN_SYSTEM_FLOW_ID = "#UF$TABLE*";
+
+    private final AtomicInteger unaccountedFlowsCounter = new AtomicInteger(0);
+
+    public StatListenCommitFlow (final StatisticsManager manager, final DataBroker db,
+            final NotificationProviderService nps){
+        super(manager, db, nps, Flow.class);
+    }
+
+    @Override
+    protected OpendaylightFlowStatisticsListener getStatNotificationListener() {
+        return this;
+    }
+
+    @Override
+    protected InstanceIdentifier<Flow> getWildCardedRegistrationPath() {
+        return InstanceIdentifier.create(Nodes.class).child(Node.class)
+                .augmentation(FlowCapableNode.class).child(Table.class).child(Flow.class);
+    }
+
+    @Override
+    public void onAggregateFlowStatisticsUpdate(final AggregateFlowStatisticsUpdate notification) {
+        final TransactionId transId = notification.getTransactionId();
+        final NodeId nodeId = notification.getId();
+        if ( ! isExpectedStatistics(transId, nodeId)) {
+            LOG.debug("STAT-MANAGER - AggregateFlowStatisticsUpdate: unregistred notification detect TransactionId {}", transId);
+            return;
+        }
+        manager.getRpcMsgManager().addNotification(notification, nodeId);
+        if (notification.isMoreReplies()) {
+            return;
+        }
+        /* check flow Capable Node and write statistics */
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction tx) {
+
+                final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
+                if (( ! txContainer.isPresent()) || txContainer.get().getNotifications() == null) {
+                    return;
+                }
+                final Optional<? extends DataObject> inputObj = txContainer.get().getConfInput();
+                if (( ! inputObj.isPresent()) || ( ! (inputObj.get() instanceof Table))) {
+                    return;
+                }
+                final Table table = (Table) inputObj.get();
+                final List<? extends TransactionAware> cacheNotifs = txContainer.get().getNotifications();
+                for (final TransactionAware notif : cacheNotifs) {
+                    if (notif instanceof AggregateFlowStatisticsUpdate) {
+                        final AggregateFlowStatisticsData stats = new AggregateFlowStatisticsDataBuilder()
+                            .setAggregateFlowStatistics(new AggregateFlowStatisticsBuilder(notification).build()).build();
+                        final InstanceIdentifier<FlowCapableNode> fNodeIdent = InstanceIdentifier.create(Nodes.class)
+                                .child(Node.class, new NodeKey(nodeId)).augmentation(FlowCapableNode.class);
+                        final InstanceIdentifier<AggregateFlowStatisticsData> tableStatRef = fNodeIdent
+                                .child(Table.class, table.getKey()).augmentation(AggregateFlowStatisticsData.class);
+                        Optional<FlowCapableNode> fNode = Optional.absent();
+                        try {
+                            fNode = tx.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet();
+                        }
+                        catch (final ReadFailedException e) {
+                            LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e);
+                            return;
+                        }
+                        if (fNode.isPresent()) {
+                            tx.put(LogicalDatastoreType.OPERATIONAL, tableStatRef, stats, true);
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) {
+        final TransactionId transId = notification.getTransactionId();
+        final NodeId nodeId = notification.getId();
+        if ( ! isExpectedStatistics(transId, nodeId)) {
+            LOG.debug("STAT-MANAGER - FlowsStatisticsUpdate: unregistred notification detect TransactionId {}", transId);
+            return;
+        }
+        manager.getRpcMsgManager().addNotification(notification, nodeId);
+        if (notification.isMoreReplies()) {
+            LOG.trace("Next notification for join txId {}", transId);
+            return;
+        }
+        /* add flow's statistics */
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction tx) {
+                final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
+                if (( ! txContainer.isPresent()) || txContainer.get().getNotifications() == null) {
+                    return;
+                }
+                final List<FlowAndStatisticsMapList> flowStats = new ArrayList<FlowAndStatisticsMapList>(10);
+                final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier.create(Nodes.class)
+                        .child(Node.class, new NodeKey(nodeId));
+                final List<? extends TransactionAware> cacheNotifs = txContainer.get().getNotifications();
+                for (final TransactionAware notif : cacheNotifs) {
+                    if (notif instanceof FlowsStatisticsUpdate) {
+                        final List<FlowAndStatisticsMapList> notifList =
+                                ((FlowsStatisticsUpdate) notif).getFlowAndStatisticsMapList();
+                        if (notifList != null) {
+                            flowStats.addAll(notifList);
+                        }
+                    }
+                }
+
+                statsFlowCommitAll(flowStats, nodeIdent, tx);
+                /* Notification for continue collecting statistics */
+                notifyToCollectNextStatistics(nodeIdent);
+            }
+        });
+    }
+
+    private void statsFlowCommitAll(final List<FlowAndStatisticsMapList> list,
+            final InstanceIdentifier<Node> nodeIdent, final ReadWriteTransaction tx) {
+
+        final InstanceIdentifier<FlowCapableNode> fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class);
+
+        final Optional<FlowCapableNode> fNode;
+        try {
+            fNode = tx.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet();
+        }
+        catch (final ReadFailedException e) {
+            LOG.debug("Read FlowCapableNode {} in Operational/DS fail! Statistic scan not be updated.", nodeIdent, e);
+            return;
+        }
+        if ( ! fNode.isPresent()) {
+            LOG.trace("FlowCapableNode {} is not presented in Operational/DS. Statisticscan not be updated.", nodeIdent);
+            return;
+        }
+
+        final NodeUpdateState nodeState = new NodeUpdateState(fNodeIdent,fNode.get());
+
+        for (final FlowAndStatisticsMapList flowStat : list) {
+            final TableKey tableKey = new TableKey(flowStat.getTableId());
+            final TableFlowUpdateState tableState = nodeState.getTable(tableKey, tx);
+            tableState.reportFlow(flowStat,tx);
+        }
+
+        for (final TableFlowUpdateState table : nodeState.getTables()) {
+            table.removeUnreportedFlows(tx);
+        }
+    }
+
+    /**
+     * Method adds statistics to Flow
+     *
+     * @param flowBuilder
+     * @param deviceFlow
+     */
+    private void addStatistics(final FlowBuilder flowBuilder, final FlowAndStatisticsMapList deviceFlow) {
+        final FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder(deviceFlow);
+        final FlowStatisticsBuilder flowStatisticsBuilder = new FlowStatisticsBuilder(stats.build());
+        final FlowStatisticsDataBuilder flowStatisticsData =new FlowStatisticsDataBuilder();
+        flowStatisticsData.setFlowStatistics(flowStatisticsBuilder.build());
+        flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+    }
+
+    /**
+     * build pseudoUnique hashCode for flow in table
+     * for future easy identification
+     */
+    static String buildHashCode(final FlowAndStatisticsMapList deviceFlow) {
+        final FlowBuilder builder = new FlowBuilder();
+        builder.setMatch(deviceFlow.getMatch());
+        builder.setCookie(deviceFlow.getCookie());
+        builder.setPriority(deviceFlow.getPriority());
+        final Flow flowForHashCode = builder.build();
+        return String.valueOf(flowForHashCode.hashCode());
+    }
+
+    private class NodeUpdateState {
+        private final InstanceIdentifier<FlowCapableNode> nodeIdentifier;
+        private final Map<TableKey,TableFlowUpdateState> tables = new HashMap<>();
+
+        public NodeUpdateState(final InstanceIdentifier<FlowCapableNode> fNodeIdent, final FlowCapableNode flowCapableNode) {
+            nodeIdentifier = fNodeIdent;
+            final List<Table> tableList = flowCapableNode.getTable();
+            if(tableList != null) {
+            for (final Table table : tableList) {
+                final TableKey tableKey = table.getKey();
+                    tables.put(tableKey, new TableFlowUpdateState(nodeIdentifier.child(Table.class,tableKey),table));
+                }
+            }
+        }
+
+        public Iterable<TableFlowUpdateState> getTables() {
+            return tables.values();
+        }
+
+        TableFlowUpdateState getTable(final TableKey key,final ReadWriteTransaction tx) {
+            TableFlowUpdateState table = tables.get(key);
+            if(table == null) {
+                table = new TableFlowUpdateState(nodeIdentifier.child(Table.class, key), null);
+                tables.put(key, table);
+            }
+            return table;
+        }
+    }
+
+    private class TableFlowUpdateState {
+        private boolean tableEnsured = false;
+        final KeyedInstanceIdentifier<Table, TableKey> tableRef;
+        final TableKey tableKey;
+        final BiMap<FlowHashIdMapKey, FlowId> flowIdByHash;
+        List<Flow> configFlows;
+
+        public TableFlowUpdateState(final KeyedInstanceIdentifier<Table, TableKey> tablePath, final Table table) {
+            tableRef = tablePath;
+            tableKey = tablePath.getKey();
+            flowIdByHash = HashBiMap.create();
+            if(table != null) {
+                final FlowHashIdMapping flowHashMapping = table.getAugmentation(FlowHashIdMapping.class);
+                if (flowHashMapping != null) {
+                    final List<FlowHashIdMap>  flowHashMap = flowHashMapping.getFlowHashIdMap() != null
+                            ? flowHashMapping.getFlowHashIdMap() : Collections.<FlowHashIdMap> emptyList();
+                    for (final FlowHashIdMap flowHashId : flowHashMap) {
+                        flowIdByHash.put(flowHashId.getKey(), flowHashId.getFlowId());
+                    }
+                }
+            }
+        }
+
+        private void ensureTable(final ReadWriteTransaction tx) {
+            if( ! tableEnsured) {
+                final FlowHashIdMapping emptyMapping = new FlowHashIdMappingBuilder()
+                    .setFlowHashIdMap(Collections.<FlowHashIdMap> emptyList()).build();
+                tx.merge(LogicalDatastoreType.OPERATIONAL, tableRef.augmentation(FlowHashIdMapping.class), emptyMapping, true);
+                tableEnsured = true;
+            }
+        }
+
+        private FlowKey searchInConfiguration(final FlowAndStatisticsMapList flowStat, final ReadWriteTransaction trans) {
+            initConfigFlows(trans);
+            final Iterator<Flow> it = configFlows.iterator();
+            while(it.hasNext()) {
+                final Flow cfgFlow = it.next();
+                final FlowKey cfgKey = cfgFlow.getKey();
+                if(flowIdByHash.inverse().containsKey(cfgKey)) {
+                    it.remove();
+                } else if(FlowComparator.flowEquals(flowStat, cfgFlow)) {
+                    it.remove();
+                    return cfgKey;
+                }
+            }
+            return null;
+        }
+
+        private void initConfigFlows(final ReadWriteTransaction trans) {
+            Optional<Table> table = readLatestConfiguration(tableRef);
+            try {
+                table = trans.read(LogicalDatastoreType.CONFIGURATION, tableRef).checkedGet();
+            } catch (final ReadFailedException e) {
+                table = Optional.absent();
+            }
+            List<Flow> localList = null;
+            if(table.isPresent()) {
+                localList = table.get().getFlow();
+            }
+            if(localList == null) {
+                configFlows = Collections.emptyList();
+            } else {
+                configFlows = new LinkedList<>(localList);
+            }
+        }
+
+        private FlowKey getFlowKeyAndRemoveHash(final FlowHashIdMapKey key) {
+            final FlowId ret = flowIdByHash.get(key);
+            if(ret != null) {
+                flowIdByHash.remove(key);
+                return new FlowKey(ret);
+            }
+            return null;
+        }
+
+        /* Returns FlowKey which doesn't exist in any DataStore for now */
+        private FlowKey makeAlienFlowKey() {
+            final StringBuilder sBuilder = new StringBuilder(ALIEN_SYSTEM_FLOW_ID)
+                .append(tableKey.getId()).append("-").append(unaccountedFlowsCounter.incrementAndGet());
+            final FlowId flowId = new FlowId(sBuilder.toString());
+            return new FlowKey(flowId);
+        }
+
+        private Map<FlowHashIdMapKey, FlowId> getRemovalList() {
+            return flowIdByHash;
+        }
+
+        void reportFlow(final FlowAndStatisticsMapList flowStat, final ReadWriteTransaction trans) {
+            ensureTable(trans);
+            final FlowHashIdMapKey hashingKey = new FlowHashIdMapKey(buildHashCode(flowStat));
+            FlowKey flowKey = getFlowKeyAndRemoveHash(hashingKey);
+            if (flowKey == null) {
+                flowKey = searchInConfiguration(flowStat, trans);
+                if ( flowKey == null) {
+                    flowKey = makeAlienFlowKey();
+                }
+                updateHashCache(trans,flowKey,hashingKey);
+            }
+            final FlowBuilder flowBuilder = new FlowBuilder(flowStat);
+            flowBuilder.setKey(flowKey);
+            addStatistics(flowBuilder, flowStat);
+            final InstanceIdentifier<Flow> flowIdent = tableRef.child(Flow.class, flowKey);
+            trans.put(LogicalDatastoreType.OPERATIONAL, flowIdent, flowBuilder.build());
+            /* check life for Alien flows */
+            if (flowKey.getId().getValue().startsWith(ALIEN_SYSTEM_FLOW_ID)) {
+                removeData(flowIdent, Integer.valueOf(5));
+            }
+        }
+
+        /* Build and deploy new FlowHashId map */
+        private void updateHashCache(final ReadWriteTransaction trans, final FlowKey flowKey, final FlowHashIdMapKey hashingKey) {
+            // TODO Auto-generated method stub
+            final FlowHashIdMapBuilder flHashIdMap = new FlowHashIdMapBuilder();
+            flHashIdMap.setFlowId(flowKey.getId());
+            flHashIdMap.setKey(hashingKey);
+            final KeyedInstanceIdentifier<FlowHashIdMap, FlowHashIdMapKey> flHashIdent = tableRef
+                    .augmentation(FlowHashIdMapping.class).child(FlowHashIdMap.class, hashingKey);
+            /* Add new FlowHashIdMap */
+            trans.put(LogicalDatastoreType.OPERATIONAL, flHashIdent, flHashIdMap.build());
+        }
+
+        void removeUnreportedFlows(final ReadWriteTransaction tx) {
+            final Map<FlowHashIdMapKey, FlowId> listForRemove = getRemovalList();
+            final Optional<Table> configTable = readLatestConfiguration(tableRef);
+            List<Flow> configFlows = Collections.emptyList();
+            if (configTable.isPresent() && configTable.get().getFlow() != null) {
+                configFlows = new ArrayList<>(configTable.get().getFlow());
+            }
+            for (final Entry<FlowHashIdMapKey, FlowId> entryForRemove : listForRemove.entrySet()) {
+                final FlowKey flowKey = new FlowKey(entryForRemove.getValue());
+                final InstanceIdentifier<Flow> flowRef = tableRef.child(Flow.class, flowKey);
+                final InstanceIdentifier<FlowStatisticsData> flowStatIdent = flowRef.augmentation(FlowStatisticsData.class);
+                if (flowKey.getId().getValue().startsWith(ALIEN_SYSTEM_FLOW_ID)) {
+                    final InstanceIdentifier<Node> nodeIdent = tableRef.firstIdentifierOf(Node.class);
+                    final Integer lifeIndex = mapNodesForDelete.get(nodeIdent).remove(flowRef);
+                    if (lifeIndex > 0) {
+                        mapNodesForDelete.get(nodeIdent).put(flowRef, Integer.valueOf(lifeIndex.intValue() - 1));
+                        break;
+                    }
+                } else {
+                    if (configFlows.remove(flowRef)) {
+                        /* Node is still presented in Config/DataStore - probably lost some multipart msg */
+                        break;
+                    }
+                }
+                final Optional<FlowStatisticsData> flowStatNodeCheck;
+                try {
+                    flowStatNodeCheck = tx.read(LogicalDatastoreType.OPERATIONAL, flowStatIdent).checkedGet();
+                }
+                catch (final ReadFailedException e) {
+                    LOG.debug("Read FlowStatistics {} in Operational/DS fail! Statisticscan not beupdated.", flowStatIdent, e);
+                    break;
+                }
+                if (flowStatNodeCheck.isPresent()) {
+                    /* Node isn't new and it has not been removed yet */
+                    final InstanceIdentifier<FlowHashIdMap> flHashIdent = tableRef.augmentation(FlowHashIdMapping.class).child(FlowHashIdMap.class, entryForRemove.getKey());
+                    tx.delete(LogicalDatastoreType.OPERATIONAL, flowRef);
+                    tx.delete(LogicalDatastoreType.OPERATIONAL, flHashIdent);
+                }
+            }
+        }
+    }
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitGroup.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitGroup.java
new file mode 100644 (file)
index 0000000..41d97f0
--- /dev/null
@@ -0,0 +1,296 @@
+/**
+ * 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.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+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.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.NodeGroupStatistics;
+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.GroupFeatures;
+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.GroupStatistics;
+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.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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager.impl
+ *
+ * StatListenCommitGroup
+ * Class is a NotifyListener for GroupStatistics and DataChangeListener for Config/DataStore for Group node.
+ * All expected (registered) GroupStatistics will be builded and commit to Operational/DataStore.
+ * DataChangeEven should call create/delete Group in Operational/DS
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class StatListenCommitGroup extends StatAbstractListenCommit<Group, OpendaylightGroupStatisticsListener>
+                                                    implements OpendaylightGroupStatisticsListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(StatListenCommitMeter.class);
+
+    public StatListenCommitGroup(final StatisticsManager manager,  final DataBroker db,
+            final NotificationProviderService nps) {
+        super(manager, db, nps, Group.class);
+    }
+
+    @Override
+    protected OpendaylightGroupStatisticsListener getStatNotificationListener() {
+        return this;
+    }
+
+    @Override
+    protected InstanceIdentifier<Group> getWildCardedRegistrationPath() {
+        return InstanceIdentifier.create(Nodes.class).child(Node.class)
+                .augmentation(FlowCapableNode.class).child(Group.class);
+    }
+
+    @Override
+    public void onGroupDescStatsUpdated(final GroupDescStatsUpdated notification) {
+        final TransactionId transId = notification.getTransactionId();
+        final NodeId nodeId = notification.getId();
+        if ( ! isExpectedStatistics(transId, nodeId)) {
+            LOG.debug("STAT-MANAGER - GroupDescStatsUpdated: unregistred notification detect TransactionId {}", transId);
+            return;
+        }
+        if (notification.isMoreReplies()) {
+            manager.getRpcMsgManager().addNotification(notification, nodeId);
+            return;
+        }
+        final List<GroupDescStats> groupStats = notification.getGroupDescStats() != null
+                ? new ArrayList<>(notification.getGroupDescStats()) : new ArrayList<GroupDescStats>(10);
+        final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
+        if (txContainer.isPresent()) {
+            final List<? extends TransactionAware> cacheNotifs =
+                    txContainer.get().getNotifications();
+            for (final TransactionAware notif : cacheNotifs) {
+                if (notif instanceof GroupDescStatsUpdated) {
+                    groupStats.addAll(((GroupDescStatsUpdated) notif).getGroupDescStats());
+                }
+            }
+        }
+        final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier
+                .create(Nodes.class).child(Node.class, new NodeKey(nodeId));
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction tx) {
+                statGroupDescCommit(groupStats, nodeIdent, tx);
+                /* Notification for continue collecting statistics */
+                notifyToCollectNextStatistics(nodeIdent);
+            }
+        });
+    }
+
+    @Override
+    public void onGroupFeaturesUpdated(final GroupFeaturesUpdated notification) {
+        final TransactionId transId = notification.getTransactionId();
+        final NodeId nodeId = notification.getId();
+        if ( ! isExpectedStatistics(transId, nodeId)) {
+            LOG.debug("STAT-MANAGER - MeterFeaturesUpdated: unregistred notification detect TransactionId {}", transId);
+            return;
+        }
+        if (notification.isMoreReplies()) {
+            manager.getRpcMsgManager().addNotification(notification, nodeId);
+            return;
+        }
+        final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
+        if ( ! txContainer.isPresent()) {
+            return;
+        }
+        final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier
+                .create(Nodes.class).child(Node.class, new NodeKey(nodeId));
+
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction tx) {
+                notifyToCollectNextStatistics(nodeIdent);
+                final GroupFeatures stats = new GroupFeaturesBuilder(notification).build();
+                final InstanceIdentifier<GroupFeatures> groupFeatureIdent = nodeIdent
+                        .augmentation(NodeGroupFeatures.class).child(GroupFeatures.class);
+                Optional<Node> node = Optional.absent();
+                try {
+                    node = tx.read(LogicalDatastoreType.OPERATIONAL, nodeIdent).checkedGet();
+                }
+                catch (final ReadFailedException e) {
+                    LOG.debug("Read Operational/DS for Node fail! {}", nodeIdent, e);
+                }
+                if (node.isPresent()) {
+                    tx.put(LogicalDatastoreType.OPERATIONAL, groupFeatureIdent, stats, true);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onGroupStatisticsUpdated(final GroupStatisticsUpdated notification) {
+        final TransactionId transId = notification.getTransactionId();
+        final NodeId nodeId = notification.getId();
+        if ( ! isExpectedStatistics(transId, nodeId)) {
+            LOG.debug("STAT-MANAGER - GroupStatisticsUpdated: unregistred notification detect TransactionId {}", transId);
+            return;
+        }
+        if (notification.isMoreReplies()) {
+            manager.getRpcMsgManager().addNotification(notification, nodeId);
+            return;
+        }
+        final List<GroupStats> groupStats = notification.getGroupStats() != null
+                ? new ArrayList<>(notification.getGroupStats()) : new ArrayList<GroupStats>(10);
+        Optional<Group> notifGroup = Optional.absent();
+        final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
+        if (txContainer.isPresent()) {
+            final Optional<? extends DataObject> inputObj = txContainer.get().getConfInput();
+            if (inputObj.isPresent() && inputObj.get() instanceof Group) {
+                notifGroup = Optional.<Group> of((Group)inputObj.get());
+            }
+            final List<? extends TransactionAware> cacheNotifs =
+                    txContainer.get().getNotifications();
+            for (final TransactionAware notif : cacheNotifs) {
+                if (notif instanceof GroupStatisticsUpdated) {
+                    groupStats.addAll(((GroupStatisticsUpdated) notif).getGroupStats());
+                }
+            }
+        }
+        final Optional<Group> group = notifGroup;
+        final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier
+                .create(Nodes.class).child(Node.class, new NodeKey(nodeId));
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction tx) {
+                /* Notification for continue collecting statistics */
+                if ( ! group.isPresent()) {
+                    notifyToCollectNextStatistics(nodeIdent);
+                }
+                statGroupCommit(groupStats, nodeIdent, group, tx);
+            }
+        });
+    }
+
+    private void statGroupCommit(final List<GroupStats> groupStats, final InstanceIdentifier<Node> nodeIdent,
+            final Optional<Group> group, final ReadWriteTransaction trans) {
+        final InstanceIdentifier<FlowCapableNode> fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class);
+
+        for (final GroupStats groupStat : groupStats) {
+            final GroupStatistics stats = new GroupStatisticsBuilder(groupStat).build();
+
+            final GroupKey groupKey = new GroupKey(groupStat.getGroupId());
+            final InstanceIdentifier<GroupStatistics> gsIdent = fNodeIdent
+                    .child(Group.class,groupKey).augmentation(NodeGroupStatistics.class)
+                    .child(GroupStatistics.class);
+            /* Statistics Writing */
+            Optional<FlowCapableNode> fNode = Optional.absent();
+            try {
+                fNode = trans.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet();
+            }
+            catch (final ReadFailedException e) {
+                LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e);
+            }
+            if (fNode.isPresent()) {
+                trans.put(LogicalDatastoreType.OPERATIONAL, gsIdent, stats, true);
+            }
+        }
+    }
+
+    private void statGroupDescCommit(final List<GroupDescStats> groupStats, final InstanceIdentifier<Node> nodeIdent,
+            final ReadWriteTransaction trans) {
+        final InstanceIdentifier<FlowCapableNode> fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class);
+
+        final List<GroupKey> deviceGroupKeys = new ArrayList<>();
+
+        for (final GroupDescStats group : groupStats) {
+            if (group.getGroupId() != null) {
+                final GroupBuilder groupBuilder = new GroupBuilder(group);
+                final GroupKey groupKey = new GroupKey(group.getGroupId());
+                final InstanceIdentifier<Group> groupRef = fNodeIdent.child(Group.class,groupKey);
+
+                final NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
+                groupDesc.setGroupDesc(new GroupDescBuilder(group).build());
+                //Update augmented data
+                groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
+                deviceGroupKeys.add(groupKey);
+                Optional<FlowCapableNode> hashIdUpd = Optional.absent();
+                try {
+                    hashIdUpd = trans.read(LogicalDatastoreType.OPERATIONAL,fNodeIdent).checkedGet();
+                }
+                catch (final ReadFailedException e) {
+                    LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e);
+                }
+                if (hashIdUpd.isPresent()) {
+                    trans.put(LogicalDatastoreType.OPERATIONAL, groupRef, groupBuilder.build());
+                }
+            }
+        }
+        /* Delete all not presented Group Nodes */
+        deleteAllNotPresentNode(fNodeIdent, trans, deviceGroupKeys);
+    }
+
+    private void deleteAllNotPresentNode(final InstanceIdentifier<FlowCapableNode> fNodeIdent,
+            final ReadWriteTransaction trans, final List<GroupKey> deviceGroupKeys) {
+
+        final Optional<FlowCapableNode> fNode = readLatestConfiguration(fNodeIdent);
+        if ( ! fNode.isPresent()) {
+            LOG.trace("Read Operational/DS for FlowCapableNode fail! Node {} doesn't exist.", fNodeIdent);
+            return;
+        }
+        final List<Group> existGroups = fNode.get().getGroup().isEmpty()
+                ? Collections.<Group> emptyList() : fNode.get().getGroup();
+        /* Add all existed groups paths - no updated paths has to be removed */
+        for (final Group group : existGroups) {
+            if (deviceGroupKeys.remove(group.getKey())) {
+                break; // group still exist on device
+            }
+            LOG.trace("Group {} has to removed.", group);
+            final InstanceIdentifier<Group> delGroupIdent = fNodeIdent.child(Group.class, group.getKey());
+            Optional<Group> delGroup = Optional.absent();
+            try {
+                delGroup = trans.read(LogicalDatastoreType.OPERATIONAL, delGroupIdent).checkedGet();
+            }
+            catch (final ReadFailedException e) {
+                // NOOP - probably another transaction delete that node
+            }
+            if (delGroup.isPresent()) {
+                trans.delete(LogicalDatastoreType.OPERATIONAL, delGroupIdent);
+            }
+        }
+    }
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitMeter.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitMeter.java
new file mode 100644 (file)
index 0000000..e2ae763
--- /dev/null
@@ -0,0 +1,283 @@
+/**
+ * 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.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+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.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 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.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.NodeMeterStatistics;
+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.MeterFeatures;
+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.MeterStatistics;
+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.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager.impl
+ *
+ * StatListenCommitMeter
+ * Class is a NotifyListener for MeterStatistics and DataChangeListener for Config/DataStore for Meter node.
+ * All expected (registered) MeterStatistics will be builded and commit to Operational/DataStore.
+ * DataChangeEven should call create/delete Meter in Operational/DS
+ *
+ */
+public class StatListenCommitMeter extends StatAbstractListenCommit<Meter, OpendaylightMeterStatisticsListener>
+                                            implements OpendaylightMeterStatisticsListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(StatListenCommitMeter.class);
+
+    public StatListenCommitMeter(final StatisticsManager manager, final DataBroker db,
+            final NotificationProviderService nps) {
+        super(manager, db, nps, Meter.class);
+    }
+
+    @Override
+    protected InstanceIdentifier<Meter> getWildCardedRegistrationPath() {
+        return InstanceIdentifier.create(Nodes.class).child(Node.class)
+                .augmentation(FlowCapableNode.class).child(Meter.class);
+    }
+
+    @Override
+    protected OpendaylightMeterStatisticsListener getStatNotificationListener() {
+        return this;
+    }
+
+    @Override
+    public void onMeterConfigStatsUpdated(final MeterConfigStatsUpdated notification) {
+        final TransactionId transId = notification.getTransactionId();
+        final NodeId nodeId = notification.getId();
+        if ( ! isExpectedStatistics(transId, nodeId)) {
+            LOG.debug("STAT-MANAGER - MeterConfigStatsUpdated: unregistred notification detect TransactionId {}", transId);
+            return;
+        }
+        if (notification.isMoreReplies()) {
+            manager.getRpcMsgManager().addNotification(notification, nodeId);
+            return;
+        }
+        final List<MeterConfigStats> meterConfStat = notification.getMeterConfigStats() != null
+                ? new ArrayList<>(notification.getMeterConfigStats()) : new ArrayList<MeterConfigStats>(10);
+        final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
+        if (txContainer.isPresent()) {
+            final List<? extends TransactionAware> cacheNotifs = txContainer.get().getNotifications();
+            for (final TransactionAware notif : cacheNotifs) {
+                if (notif instanceof MeterConfigStatsUpdated) {
+                    meterConfStat.addAll(((MeterConfigStatsUpdated) notif).getMeterConfigStats());
+                }
+            }
+        }
+        final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(nodeId));
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction tx) {
+                /* Notification for continue collecting statistics */
+                notifyToCollectNextStatistics(nodeIdent);
+                comitConfMeterStats(meterConfStat, nodeIdent, tx);
+            }
+        });
+    }
+
+    @Override
+    public void onMeterFeaturesUpdated(final MeterFeaturesUpdated notification) {
+        final TransactionId transId = notification.getTransactionId();
+        final NodeId nodeId = notification.getId();
+        if ( ! isExpectedStatistics(transId, nodeId)) {
+            LOG.debug("STAT-MANAGER - MeterFeaturesUpdated: unregistred notification detect TransactionId {}", transId);
+            return;
+        }
+        if (notification.isMoreReplies()) {
+            manager.getRpcMsgManager().addNotification(notification, nodeId);
+            return;
+        }
+        final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
+        if ( ! txContainer.isPresent()) {
+            return;
+        }
+        final MeterFeatures stats = new MeterFeaturesBuilder(notification).build();
+        final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier
+                .create(Nodes.class).child(Node.class, new NodeKey(nodeId));
+        final InstanceIdentifier<MeterFeatures> meterFeatureIdent = nodeIdent
+                .augmentation(NodeMeterFeatures.class).child(MeterFeatures.class);
+
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction tx) {
+                /* Notification for continue collecting statistics */
+                notifyToCollectNextStatistics(nodeIdent);
+                Optional<Node> node = Optional.absent();
+                try {
+                    node = tx.read(LogicalDatastoreType.OPERATIONAL, nodeIdent).checkedGet();
+                }
+                catch (final ReadFailedException e) {
+                    LOG.debug("Read Operational/DS for Node fail! {}", nodeIdent, e);
+                }
+                if (node.isPresent()) {
+                    tx.put(LogicalDatastoreType.OPERATIONAL, meterFeatureIdent, stats, true);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onMeterStatisticsUpdated(final MeterStatisticsUpdated notification) {
+        final TransactionId transId = notification.getTransactionId();
+        final NodeId nodeId = notification.getId();
+        if ( ! isExpectedStatistics(transId, nodeId)) {
+            LOG.debug("STAT-MANAGER - MeterStatisticsUpdated: unregistred notification detect TransactionId {}", transId);
+            return;
+        }
+        if (notification.isMoreReplies()) {
+            manager.getRpcMsgManager().addNotification(notification, nodeId);
+            return;
+        }
+        final List<MeterStats> meterStat = notification.getMeterStats() != null
+                ? new ArrayList<>(notification.getMeterStats()) : new ArrayList<MeterStats>(10);
+        final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
+        if (txContainer.isPresent()) {
+            final List<? extends TransactionAware> cacheNotifs = txContainer.get().getNotifications();
+            for (final TransactionAware notif : cacheNotifs) {
+                if (notif instanceof MeterConfigStatsUpdated) {
+                    meterStat.addAll(((MeterStatisticsUpdated) notif).getMeterStats());
+                }
+            }
+        }
+        final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(nodeId));
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction tx) {
+                statMeterCommit(meterStat, nodeIdent, tx);
+                /* Notification for continue collecting statistics */
+                notifyToCollectNextStatistics(nodeIdent);
+            }
+        });
+    }
+
+    private void statMeterCommit(final List<MeterStats> meterStats,
+            final InstanceIdentifier<Node> nodeIdent, final ReadWriteTransaction trans) {
+
+        final InstanceIdentifier<FlowCapableNode> fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class);
+        for (final MeterStats mStat : meterStats) {
+            final MeterStatistics stats = new MeterStatisticsBuilder(mStat).build();
+
+            final MeterKey mKey = new MeterKey(mStat.getMeterId());
+            final InstanceIdentifier<MeterStatistics> msIdent = fNodeIdent
+                    .child(Meter.class, mKey).augmentation(NodeMeterStatistics.class)
+                    .child(MeterStatistics.class);
+            /* Meter Statistics commit */
+            Optional<FlowCapableNode> fNode = Optional.absent();
+            try {
+                fNode = trans.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet();
+            }
+            catch (final ReadFailedException e) {
+                LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e);
+            }
+            if (fNode.isPresent()) {
+                trans.put(LogicalDatastoreType.OPERATIONAL, msIdent, stats, true);
+            }
+        }
+    }
+
+    private void comitConfMeterStats(final List<MeterConfigStats> meterConfStat,
+            final InstanceIdentifier<Node> nodeIdent, final ReadWriteTransaction trans) {
+
+        final InstanceIdentifier<FlowCapableNode> fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class);
+        final List<MeterKey> deviceMeterKeys = new ArrayList<>();
+
+        for (final MeterConfigStats meterConf : meterConfStat) {
+            final MeterBuilder meterBuilder = new MeterBuilder(meterConf);
+            if (meterConf.getMeterId() != null) {
+                final MeterKey meterKey = new MeterKey(meterConf.getMeterId());
+                meterBuilder.setKey(meterKey);
+                final InstanceIdentifier<Meter> meterRef = nodeIdent
+                        .augmentation(FlowCapableNode.class).child(Meter.class,meterKey);
+                final NodeMeterConfigStatsBuilder meterConfig = new NodeMeterConfigStatsBuilder();
+                meterConfig.setMeterConfigStats(new MeterConfigStatsBuilder(meterConf).build());
+                //Update augmented data
+                meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
+                deviceMeterKeys.add(meterKey);
+                Optional<FlowCapableNode> fNode = Optional.absent();
+                try {
+                    fNode = trans.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet();
+                }
+                catch (final ReadFailedException e) {
+                    LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e);
+                }
+                if (fNode.isPresent()) {
+                    trans.put(LogicalDatastoreType.OPERATIONAL, meterRef, meterBuilder.build());
+                }
+            }
+        }
+        /* Delete all not presented Meter Nodes */
+        deleteAllNotPresentedNodes(fNodeIdent, trans, deviceMeterKeys);
+    }
+
+    private void deleteAllNotPresentedNodes(final InstanceIdentifier<FlowCapableNode> fNodeIdent,
+            final ReadWriteTransaction trans, final List<MeterKey> deviceMeterKeys) {
+        /* Delete all not presented meters */
+        final Optional<FlowCapableNode> fNode = readLatestConfiguration(fNodeIdent);
+
+        if ( ! fNode.isPresent()) {
+            LOG.trace("Read Operational/DS for FlowCapableNode fail! Node {} doesn't exist.", fNodeIdent);
+            return;
+        }
+        final List<Meter> existMeters = fNode.get().getMeter().isEmpty()
+                ? Collections.<Meter> emptyList() : fNode.get().getMeter();
+        /* Add all existed groups paths - no updated paths has to be removed */
+        for (final Meter meter : existMeters) {
+            if (deviceMeterKeys.remove(meter.getKey())) {
+                break; // Meter still exist on device
+            }
+            final InstanceIdentifier<Meter> delMeterIdent = fNodeIdent.child(Meter.class, meter.getKey());
+            Optional<Meter> delMeter = Optional.absent();
+            try {
+                delMeter = trans.read(LogicalDatastoreType.OPERATIONAL, delMeterIdent).checkedGet();
+            }
+            catch (final ReadFailedException e) {
+                // NOOP - probably another transaction delete that node
+            }
+            if (delMeter.isPresent()) {
+                trans.delete(LogicalDatastoreType.OPERATIONAL, delMeterIdent);
+            }
+        }
+    }
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitQueue.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatListenCommitQueue.java
new file mode 100644 (file)
index 0000000..29fe5d8
--- /dev/null
@@ -0,0 +1,149 @@
+/**
+ * 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.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+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.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.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.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.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.FlowCapableNodeConnectorQueueStatistics;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager.impl
+ *
+ * StatNotifyCommitQueue
+ * Class is a NotifyListner for Queues Statistics
+ * All expected (registered) queueStatistics will be builded and
+ * commit to Operational/DataStore
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class StatListenCommitQueue extends StatAbstractListenCommit<Queue, OpendaylightQueueStatisticsListener>
+                                        implements OpendaylightQueueStatisticsListener {
+
+    private final static Logger LOG = LoggerFactory.getLogger(StatListenCommitQueue.class);
+
+    public StatListenCommitQueue(final StatisticsManager manager, final DataBroker db,
+            final NotificationProviderService nps) {
+        super(manager, db, nps, Queue.class);
+    }
+
+    @Override
+    protected OpendaylightQueueStatisticsListener getStatNotificationListener() {
+        return this;
+    }
+
+    @Override
+    protected InstanceIdentifier<Queue> getWildCardedRegistrationPath() {
+        return InstanceIdentifier.create(Nodes.class).child(Node.class).child(NodeConnector.class)
+            .augmentation(FlowCapableNodeConnector.class).child(Queue.class);
+    }
+
+    @Override
+    public void onQueueStatisticsUpdate(final QueueStatisticsUpdate notification) {
+        final TransactionId transId = notification.getTransactionId();
+        final NodeId nodeId = notification.getId();
+        if ( ! isExpectedStatistics(transId, nodeId)) {
+            LOG.debug("STAT-MANAGER - QueueStatisticsUpdate: unregistred notification detect TransactionId {}", transId);
+            return;
+        }
+        if (notification.isMoreReplies()) {
+            manager.getRpcMsgManager().addNotification(notification, nodeId);
+            return;
+        }
+        final List<QueueIdAndStatisticsMap> queueStats = notification.getQueueIdAndStatisticsMap() != null
+                ? new ArrayList<>(notification.getQueueIdAndStatisticsMap()) : new ArrayList<QueueIdAndStatisticsMap>(10);
+        final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
+        if (txContainer.isPresent()) {
+            final List<? extends TransactionAware> cachedNotifs =
+                    txContainer.get().getNotifications();
+            for (final TransactionAware notif : cachedNotifs) {
+                if (notif instanceof QueueStatisticsUpdate) {
+                    queueStats.addAll(((QueueStatisticsUpdate) notif).getQueueIdAndStatisticsMap());
+                }
+            }
+        }
+        final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier.create(Nodes.class)
+                .child(Node.class, new NodeKey(nodeId));
+        /* Queue statistics are small size and we are not able to change for OF cross controller
+         * - don't need to make are atomic */
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction trans) {
+                /* Notification for continue */
+                notifyToCollectNextStatistics(nodeIdent);
+                statQueueCommit(queueStats, nodeIdent, trans);
+            }
+        });
+    }
+
+    private void statQueueCommit(final List<QueueIdAndStatisticsMap> queueStats,
+            final InstanceIdentifier<Node> nodeIdent, final ReadWriteTransaction trans) {
+
+        /* check exist FlowCapableNode and write statistics */
+        Optional<Node> fNode = Optional.absent();
+        try {
+            fNode = trans.read(LogicalDatastoreType.OPERATIONAL, nodeIdent).checkedGet();
+        }
+        catch (final ReadFailedException e) {
+            LOG.debug("Read Operational/DS for Node fail! {}", nodeIdent, e);
+            return;
+        }
+        if ( ! fNode.isPresent()) {
+            LOG.trace("Read Operational/DS for Node fail! Node {} doesn't exist.", nodeIdent);
+            return;
+        }
+
+        for (final QueueIdAndStatisticsMap queueEntry : queueStats) {
+            final FlowCapableNodeConnectorQueueStatistics statChild =
+                    new FlowCapableNodeConnectorQueueStatisticsBuilder(queueEntry).build();
+            final FlowCapableNodeConnectorQueueStatisticsDataBuilder statBuild =
+                    new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
+            statBuild.setFlowCapableNodeConnectorQueueStatistics(statChild);
+            final QueueKey qKey = new QueueKey(queueEntry.getQueueId());
+            final InstanceIdentifier<FlowCapableNodeConnectorQueueStatisticsData> queueStatIdent = nodeIdent
+                    .child(NodeConnector.class, new NodeConnectorKey(queueEntry.getNodeConnectorId()))
+                    .augmentation(FlowCapableNodeConnector.class)
+                    .child(Queue.class, qKey).augmentation(FlowCapableNodeConnectorQueueStatisticsData.class);
+            trans.put(LogicalDatastoreType.OPERATIONAL, queueStatIdent, statBuild.build(), true);
+        }
+    }
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNodeRegistrationImpl.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNodeRegistrationImpl.java
new file mode 100644 (file)
index 0000000..adb5870
--- /dev/null
@@ -0,0 +1,207 @@
+/**
+ * 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.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+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.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.statistics.manager.StatNodeRegistration;
+import org.opendaylight.controller.md.statistics.manager.StatPermCollector.StatCapabTypes;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FeatureCapability;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityFlowStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityGroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityPortStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityQueueStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityTableStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SwitchFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
+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.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager.impl
+ *
+ * StatNodeRegistrationImpl
+ * {@link FlowCapableNode} Registration Implementation contains two method for registration/unregistration
+ * {@link FeatureCapability} for every connect/disconnect {@link FlowCapableNode}. Process of connection/disconnection
+ * is substituted by listening Operation/DS for add/delete {@link FeatureCapability}.
+ * All statistic capabilities are reading from new Node directly without contacting device or DS.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Aug 28, 2014
+ */
+public class StatNodeRegistrationImpl implements StatNodeRegistration {
+
+    private static final Logger LOG = LoggerFactory.getLogger(StatNodeRegistrationImpl.class);
+
+    private final StatisticsManager manager;
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private ListenerRegistration<?> notifListenerRegistration;
+
+    public StatNodeRegistrationImpl(final StatisticsManager manager, final DataBroker db,
+            final NotificationProviderService notificationService) {
+        this.manager = Preconditions.checkNotNull(manager, "StatisticManager can not be null!");
+        Preconditions.checkArgument(db != null, "DataBroker can not be null!");
+        Preconditions.checkArgument(notificationService != null, "NotificationProviderService can not be null!");
+        notifListenerRegistration = notificationService.registerNotificationListener(this);
+    }
+
+    @Override
+    public void close() throws Exception {
+
+        if (notifListenerRegistration != null) {
+            try {
+                notifListenerRegistration.close();
+            }
+            catch (final Exception e) {
+                LOG.warn("Error by stop FlowCapableNode Notification StatNodeRegistration.");
+            }
+            notifListenerRegistration = null;
+        }
+
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.warn("Error by stop FlowCapableNode DataChange StatListeningCommiter.", e);
+            }
+            listenerRegistration = null;
+        }
+    }
+
+    @Override
+    public void connectFlowCapableNode(final InstanceIdentifier<SwitchFeatures> keyIdent,
+            final SwitchFeatures data, final InstanceIdentifier<Node> nodeIdent) {
+        Preconditions.checkNotNull(keyIdent, "InstanceIdentifier can not be null!");
+        Preconditions.checkNotNull(data, "SwitchFeatures data for {} can not be null!", keyIdent);
+        Preconditions.checkArgument(( ! keyIdent.isWildcarded()), "InstanceIdentifier is WildCarded!");
+
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction tx) {
+
+                final List<StatCapabTypes> statCapabTypes = new ArrayList<>();
+                Short maxCapTables = Short.valueOf("1");
+
+                final List<Class<? extends FeatureCapability>> capabilities = data.getCapabilities() != null
+                        ? data.getCapabilities() : Collections.<Class<? extends FeatureCapability>> emptyList();
+                for (final Class<? extends FeatureCapability> capability : capabilities) {
+                    if (capability == FlowFeatureCapabilityTableStats.class) {
+                        statCapabTypes.add(StatCapabTypes.TABLE_STATS);
+                    } else if (capability == FlowFeatureCapabilityFlowStats.class) {
+                        statCapabTypes.add(StatCapabTypes.FLOW_STATS);
+                    } else if (capability == FlowFeatureCapabilityGroupStats.class) {
+                        statCapabTypes.add(StatCapabTypes.GROUP_STATS);
+                    } else if (capability == FlowFeatureCapabilityPortStats.class) {
+                        statCapabTypes.add(StatCapabTypes.PORT_STATS);
+                    } else if (capability == FlowFeatureCapabilityQueueStats.class) {
+                        statCapabTypes.add(StatCapabTypes.QUEUE_STATS);
+                    }
+                }
+                maxCapTables = data.getMaxTables();
+
+                final Optional<Short> maxTables = Optional.<Short> of(maxCapTables);
+
+                /* Meters management */
+                final InstanceIdentifier<NodeMeterFeatures> meterFeaturesIdent = nodeIdent.augmentation(NodeMeterFeatures.class);
+
+
+                Optional<NodeMeterFeatures> meterFeatures = Optional.absent();
+                try {
+                    meterFeatures = tx.read(LogicalDatastoreType.OPERATIONAL, meterFeaturesIdent).checkedGet();
+                }
+                catch (final ReadFailedException e) {
+                    LOG.warn("Read NodeMeterFeatures {} fail!", meterFeaturesIdent, e);
+                }
+                if (meterFeatures.isPresent()) {
+                    statCapabTypes.add(StatCapabTypes.METER_STATS);
+                }
+                manager.connectedNodeRegistration(nodeIdent,
+                        Collections.unmodifiableList(statCapabTypes), maxTables.get());
+            }
+        });
+    }
+
+    @Override
+    public void disconnectFlowCapableNode(final InstanceIdentifier<Node> nodeIdent) {
+        Preconditions.checkArgument(nodeIdent != null, "InstanceIdentifier can not be NULL!");
+        Preconditions.checkArgument(( ! nodeIdent.isWildcarded()),
+                "InstanceIdentifier {} is WildCarded!", nodeIdent);
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction tx) {
+                manager.disconnectedNodeUnregistration(nodeIdent);
+            }
+        });
+    }
+
+
+    @Override
+    public void onNodeConnectorRemoved(final NodeConnectorRemoved notification) {
+        // NOOP
+    }
+
+    @Override
+    public void onNodeConnectorUpdated(final NodeConnectorUpdated notification) {
+        // NOOP
+    }
+
+    @Override
+    public void onNodeRemoved(final NodeRemoved notification) {
+        final NodeRef nodeRef = notification.getNodeRef();
+        final InstanceIdentifier<?> nodeRefIdent = nodeRef.getValue();
+        final InstanceIdentifier<Node> nodeIdent =
+                nodeRefIdent.firstIdentifierOf(Node.class);
+        if (nodeIdent != null) {
+            disconnectFlowCapableNode(nodeIdent);
+        }
+    }
+
+    @Override
+    public void onNodeUpdated(final NodeUpdated notification) {
+        final FlowCapableNodeUpdated newFlowNode =
+                notification.getAugmentation(FlowCapableNodeUpdated.class);
+        if (newFlowNode != null && newFlowNode.getSwitchFeatures() != null) {
+            final NodeRef nodeRef = notification.getNodeRef();
+            final InstanceIdentifier<?> nodeRefIdent = nodeRef.getValue();
+            final InstanceIdentifier<Node> nodeIdent =
+                    nodeRefIdent.firstIdentifierOf(Node.class);
+
+            final InstanceIdentifier<SwitchFeatures> swichFeaturesIdent =
+                    nodeIdent.augmentation(FlowCapableNode.class).child(SwitchFeatures.class);
+            final SwitchFeatures switchFeatures = newFlowNode.getSwitchFeatures();
+            connectFlowCapableNode(swichFeaturesIdent, switchFeatures, nodeIdent);
+        }
+    }
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNotifyCommitPort.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNotifyCommitPort.java
new file mode 100644 (file)
index 0000000..72c10ee
--- /dev/null
@@ -0,0 +1,148 @@
+/**
+ * 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.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+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 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.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.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager.impl
+ *
+ * StatNotifyCommitPort
+ * Class is a NotifyListener for PortStatistics
+ * All expected (registered) portStatistics will be builded and
+ * commit to Operational/DataStore
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class StatNotifyCommitPort extends StatAbstractNotifyCommit<OpendaylightPortStatisticsListener>
+                                        implements OpendaylightPortStatisticsListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(StatNotifyCommitPort.class);
+
+    public StatNotifyCommitPort(final StatisticsManager manager,
+            final NotificationProviderService nps) {
+        super(manager, nps);
+    }
+
+    @Override
+    protected OpendaylightPortStatisticsListener getStatNotificationListener() {
+        return this;
+    }
+
+    @Override
+    public void onNodeConnectorStatisticsUpdate(final NodeConnectorStatisticsUpdate notification) {
+        final TransactionId transId = notification.getTransactionId();
+        final NodeId nodeId = notification.getId();
+        if ( ! isExpectedStatistics(transId, nodeId)) {
+            LOG.debug("STAT-MANAGER - NodeConnectorStatisticsUpdate: unregistred notification detect TransactionId {}", transId);
+            return;
+        }
+        manager.getRpcMsgManager().addNotification(notification, nodeId);
+        if (notification.isMoreReplies()) {
+            return;
+        }
+        final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier.create(Nodes.class)
+                .child(Node.class, new NodeKey(nodeId));
+        /* Don't block RPC Notification thread */
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction trans) {
+                final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
+                if (( ! txContainer.isPresent()) || txContainer.get().getNotifications() == null) {
+                    return;
+                }
+                final List<NodeConnectorStatisticsAndPortNumberMap> portStats =
+                        new ArrayList<NodeConnectorStatisticsAndPortNumberMap>(10);
+                final List<? extends TransactionAware> cachedNotifs = txContainer.get().getNotifications();
+                for (final TransactionAware notif : cachedNotifs) {
+                    if (notif instanceof NodeConnectorStatisticsUpdate) {
+                        final List<NodeConnectorStatisticsAndPortNumberMap> notifStat =
+                                ((NodeConnectorStatisticsUpdate) notif).getNodeConnectorStatisticsAndPortNumberMap();
+                        if (notifStat != null) {
+                            portStats.addAll(notifStat);
+                        }
+                    }
+                }
+                /* write stat to trans */
+                statPortCommit(portStats, nodeIdent, trans);
+                /* Notification for continue collecting statistics - Port statistics are still same size
+                 * and they are small - don't need to wait for whole apply operation*/
+                notifyToCollectNextStatistics(nodeIdent);
+            }
+        });
+    }
+
+    private void statPortCommit(final List<NodeConnectorStatisticsAndPortNumberMap> portStats,
+            final InstanceIdentifier<Node> nodeIdent, final ReadWriteTransaction tx) {
+
+        /* check exist FlowCapableNode and write statistics probable with parent */
+        Optional<Node> fNode = Optional.absent();
+        try {
+            fNode = tx.read(LogicalDatastoreType.OPERATIONAL, nodeIdent).checkedGet();
+        }
+        catch (final ReadFailedException e) {
+            LOG.debug("Read Operational/DS for Node fail! {}", nodeIdent, e);
+            return;
+        }
+        if ( ! fNode.isPresent()) {
+            LOG.trace("Read Operational/DS for Node fail! Node {} doesn't exist.", nodeIdent);
+            return;
+        }
+        for (final NodeConnectorStatisticsAndPortNumberMap nConnectPort : portStats) {
+            final FlowCapableNodeConnectorStatisticsData stats = new FlowCapableNodeConnectorStatisticsDataBuilder()
+                    .setFlowCapableNodeConnectorStatistics(new FlowCapableNodeConnectorStatisticsBuilder(nConnectPort).build()).build();
+            final NodeConnectorKey key = new NodeConnectorKey(nConnectPort.getNodeConnectorId());
+            final InstanceIdentifier<NodeConnector> nodeConnectorIdent = nodeIdent.child(NodeConnector.class, key);
+            final InstanceIdentifier<FlowCapableNodeConnectorStatisticsData> nodeConnStatIdent = nodeConnectorIdent
+                    .augmentation(FlowCapableNodeConnectorStatisticsData.class);
+            Optional<NodeConnector> fNodeConector;
+            try {
+                fNodeConector = tx.read(LogicalDatastoreType.OPERATIONAL, nodeConnectorIdent).checkedGet();
+            }
+            catch (final ReadFailedException e) {
+                LOG.debug("Read NodeConnector {} in Operational/DS fail!", nodeConnectorIdent, e);
+                fNodeConector = Optional.absent();
+            }
+            if (fNodeConector.isPresent()) {
+                tx.put(LogicalDatastoreType.OPERATIONAL, nodeConnStatIdent, stats);
+            }
+        }
+    }
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNotifyCommitTable.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatNotifyCommitTable.java
new file mode 100644 (file)
index 0000000..3210934
--- /dev/null
@@ -0,0 +1,138 @@
+/**
+ * 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.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+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.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.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.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 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.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager.impl
+ *
+ * StatNotifyCommitTable
+ * Class is a NotifyListener for TableStatistics
+ * All expected (registered) tableStatistics will be builded and
+ * commit to Operational/DataStore
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class StatNotifyCommitTable extends StatAbstractNotifyCommit<OpendaylightFlowTableStatisticsListener>
+                                        implements OpendaylightFlowTableStatisticsListener {
+
+    private final static Logger LOG = LoggerFactory.getLogger(StatNotifyCommitTable.class);
+
+    public StatNotifyCommitTable(final StatisticsManager manager,
+            final NotificationProviderService nps) {
+        super(manager, nps);
+    }
+
+    @Override
+    protected OpendaylightFlowTableStatisticsListener getStatNotificationListener() {
+        return this;
+    }
+
+    @Override
+    public void onFlowTableStatisticsUpdate(final FlowTableStatisticsUpdate notification) {
+        final TransactionId transId = notification.getTransactionId();
+        final NodeId nodeId = notification.getId();
+        if ( ! isExpectedStatistics(transId, nodeId)) {
+            LOG.debug("STAT-MANAGER - FlowTableStatisticsUpdate: unregistred notification detect TransactionId {}", transId);
+            return;
+        }
+        manager.getRpcMsgManager().addNotification(notification, nodeId);
+        if (notification.isMoreReplies()) {
+            return;
+        }
+        /* Don't block RPC Notification thread */
+        manager.enqueue(new StatDataStoreOperation() {
+            @Override
+            public void applyOperation(final ReadWriteTransaction trans) {
+                final List<FlowTableAndStatisticsMap> tableStats = new ArrayList<FlowTableAndStatisticsMap>(10);
+                final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
+                final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier.create(Nodes.class)
+                        .child(Node.class, new NodeKey(nodeId));
+                if (( ! txContainer.isPresent()) || txContainer.get().getNodeId() == null) {
+                    return;
+                }
+                final List<? extends TransactionAware> cachedNotifs = txContainer.get().getNotifications();
+                for (final TransactionAware notif : cachedNotifs) {
+                    if (notif instanceof FlowTableStatisticsUpdate) {
+                        final List<FlowTableAndStatisticsMap> statNotif =
+                                ((FlowTableStatisticsUpdate) notif).getFlowTableAndStatisticsMap();
+                        if (statNotif != null) {
+                            tableStats.addAll(statNotif);
+                        }
+                    }
+                }
+                /* write stat to trans */
+                statTableCommit(tableStats, nodeIdent, trans);
+                /* Notification for continue collecting statistics - Tables statistics are still same size
+                 * and they are small - don't need to wait to whole apply operation */
+                notifyToCollectNextStatistics(nodeIdent);
+            }
+        });
+    }
+
+    private void statTableCommit(final List<FlowTableAndStatisticsMap> tableStats, final InstanceIdentifier<Node> nodeIdent,
+            final ReadWriteTransaction trans) {
+        final InstanceIdentifier<FlowCapableNode> fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class);
+        /* check flow Capable Node and write statistics */
+        Optional<FlowCapableNode> fNode = Optional.absent();
+        try {
+            fNode = trans.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet();
+        }
+        catch (final ReadFailedException e) {
+            LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e);
+            return;
+        }
+        if ( ! fNode.isPresent()) {
+            LOG.trace("Read Operational/DS for FlowCapableNode fail! Node {} doesn't exist.", fNodeIdent);
+            return;
+        }
+        for (final FlowTableAndStatisticsMap tableStat : tableStats) {
+            final FlowTableStatisticsData stats = new FlowTableStatisticsDataBuilder()
+                    .setFlowTableStatistics(new FlowTableStatisticsBuilder(tableStat).build()).build();
+
+            final InstanceIdentifier<FlowTableStatisticsData> tStatIdent = fNodeIdent
+                    .child(Table.class, new TableKey(tableStat.getTableId().getValue()))
+                    .augmentation(FlowTableStatisticsData.class);
+            trans.put(LogicalDatastoreType.OPERATIONAL, tStatIdent, stats, true);
+        }
+    }
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatPermCollectorImpl.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatPermCollectorImpl.java
new file mode 100644 (file)
index 0000000..d008042
--- /dev/null
@@ -0,0 +1,305 @@
+package org.opendaylight.controller.md.statistics.manager.impl;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+import org.opendaylight.controller.md.statistics.manager.StatPermCollector;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
+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.table.types.rev131026.TableId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager.impl
+ *
+ * StatPermCollectorImpl
+ * Thread base statistic collector. Class holds internal map for all registered
+ * (means connected) nodes with List of Switch capabilities;
+ * Statistics collecting process get cross whole Network Device by device
+ * and statistic by statistic (follow Switch capabilities to prevent unnecessary
+ * ask) Next statistic start collecting by notification or by timeout.
+ *
+ * @author @author avishnoi@in.ibm.com <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class StatPermCollectorImpl implements StatPermCollector {
+
+    private final static Logger LOG = LoggerFactory.getLogger(StatPermCollectorImpl.class);
+
+    private final static long STAT_COLLECT_TIME_OUT = 30000L;
+
+    private final ExecutorService statNetCollectorServ;
+    private final StatisticsManager manager;
+
+    private final int maxNodeForCollector;
+    private final long minReqNetInterval;
+    private final String name;
+
+    private final Object statCollectorLock = new Object();
+    private final Object statNodeHolderLock = new Object();
+
+    private Map<InstanceIdentifier<Node>, StatNodeInfoHolder> statNodeHolder =
+            Collections.<InstanceIdentifier<Node>, StatNodeInfoHolder> emptyMap();
+
+    private volatile boolean wakeMe = false;
+    private volatile boolean finishing = false;
+
+    public StatPermCollectorImpl(final StatisticsManager manager, final long minReqNetInterv, final int nr,
+            final int maxNodeForCollectors) {
+        this.manager = Preconditions.checkNotNull(manager, "StatisticsManager can not be null!");
+        name = "odl-stat-collector-" + nr;
+        minReqNetInterval = minReqNetInterv;
+        final ThreadFactory threadFact = new ThreadFactoryBuilder()
+            .setNameFormat(name + "-thread-%d").build();
+        statNetCollectorServ = Executors.newSingleThreadExecutor(threadFact);
+        maxNodeForCollector = maxNodeForCollectors;
+        LOG.trace("StatCollector {} start successfull!", name);
+    }
+
+    /**
+     * finish collecting statistics
+     */
+    @Override
+    public void close() {
+        statNodeHolder = Collections.<InstanceIdentifier<Node>, StatNodeInfoHolder> emptyMap();
+        finishing = true;
+        collectNextStatistics();
+        statNetCollectorServ.shutdown();
+    }
+
+    @Override
+    public boolean isProvidedFlowNodeActive(
+            final InstanceIdentifier<Node> flowNode) {
+        return statNodeHolder.containsKey(flowNode);
+    }
+
+    @Override
+    public boolean connectedNodeRegistration(final InstanceIdentifier<Node> ident,
+            final List<StatCapabTypes> statTypes, final Short nrOfSwitchTables) {
+        if (ident.isWildcarded()) {
+            LOG.warn("FlowCapableNode IstanceIdentifier {} registration can not be wildcarded!", ident);
+        } else {
+            if ( ! statNodeHolder.containsKey(ident)) {
+                synchronized (statNodeHolderLock) {
+                    final boolean startStatCollecting = statNodeHolder.size() == 0;
+                    if ( ! statNodeHolder.containsKey(ident)) {
+                        if (statNodeHolder.size() >= maxNodeForCollector) {
+                            return false;
+                        }
+                        final Map<InstanceIdentifier<Node>, StatNodeInfoHolder> statNode =
+                                new HashMap<>(statNodeHolder);
+                        final NodeRef nodeRef = new NodeRef(ident);
+                        final StatNodeInfoHolder nodeInfoHolder = new StatNodeInfoHolder(nodeRef,
+                                statTypes, nrOfSwitchTables);
+                        statNode.put(ident, nodeInfoHolder);
+                        statNodeHolder = Collections.unmodifiableMap(statNode);
+                    }
+                    if (startStatCollecting) {
+                        finishing = false;
+                        statNetCollectorServ.execute(this);
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean disconnectedNodeUnregistration(final InstanceIdentifier<Node> ident) {
+        if (ident.isWildcarded()) {
+            LOG.warn("FlowCapableNode IstanceIdentifier {} unregistration can not be wildcarded!", ident);
+        } else {
+            if (statNodeHolder.containsKey(ident)) {
+                synchronized (statNodeHolderLock) {
+                    if (statNodeHolder.containsKey(ident)) {
+                        final Map<InstanceIdentifier<Node>, StatNodeInfoHolder> statNode =
+                                new HashMap<>(statNodeHolder);
+                        statNode.remove(ident);
+                        statNodeHolder = Collections.unmodifiableMap(statNode);
+                    }
+                    if (statNodeHolder.isEmpty()) {
+                        finishing = true;
+                        collectNextStatistics();
+                        statNetCollectorServ.shutdown();
+                    }
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void collectNextStatistics() {
+        if (wakeMe) {
+            synchronized (statCollectorLock) {
+                if (wakeMe) {
+                    LOG.trace("STAT-COLLECTOR is notified to conntinue");
+                    statCollectorLock.notify();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void run() {
+        try {
+            Thread.sleep(5000);
+        }
+        catch (final InterruptedException e1) {
+            // NOOP
+        }
+        LOG.debug("StatCollector {} Start collecting!", name);
+         /* Neverending cyle - wait for finishing */
+         while ( ! finishing) {
+            boolean collecting = false;
+            final long startTime = System.currentTimeMillis();
+
+            if ( ! statNodeHolder.isEmpty()) {
+                collecting = true;
+                collectStatCrossNetwork();
+                collecting = false;
+            }
+
+            if ( ! collecting) {
+                final long statFinalTime = System.currentTimeMillis() - startTime;
+                LOG.debug("STAT-MANAGER {}: last all NET statistics collection cost {} ms", name, statFinalTime);
+                if (statFinalTime < minReqNetInterval) {
+                    LOG.trace("statCollector is about to make a collecting sleep");
+                    synchronized (statCollectorLock) {
+                        wakeMe = true;
+                        try {
+                            final long waitTime = minReqNetInterval - statFinalTime;
+                            statCollectorLock.wait(waitTime);
+                            LOG.trace("STAT-MANAGER : statCollector {} is waking up from a collecting sleep for {} ms", name, waitTime);
+                        } catch (final InterruptedException e) {
+                            LOG.warn("statCollector has been interrupted during collecting sleep", e);
+                        } finally {
+                            wakeMe = false;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private void waitingForNotification() {
+        synchronized (statCollectorLock) {
+            wakeMe = true;
+            try {
+                statCollectorLock.wait(STAT_COLLECT_TIME_OUT);
+                LOG.trace("statCollector is waking up from a wait stat Response sleep");
+            } catch (final InterruptedException e) {
+                LOG.warn("statCollector has been interrupted waiting stat Response sleep", e);
+            } finally {
+                wakeMe = false;
+            }
+        }
+    }
+
+
+    private void collectStatCrossNetwork() {
+        for (final Entry<InstanceIdentifier<Node>, StatNodeInfoHolder> nodeEntity : statNodeHolder.entrySet()) {
+            final List<StatCapabTypes> listNeededStat = nodeEntity.getValue().getStatMarkers();
+            final NodeRef actualNodeRef = nodeEntity.getValue().getNodeRef();
+            final Short maxTables = nodeEntity.getValue().getMaxTables();
+            for (final StatCapabTypes statMarker : listNeededStat) {
+                if ( ! isProvidedFlowNodeActive(nodeEntity.getKey())) {
+                    break;
+                }
+                switch (statMarker) {
+                case PORT_STATS:
+                    LOG.trace("STAT-MANAGER-collecting PORT-STATS for NodeRef {}", actualNodeRef);
+                    manager.getRpcMsgManager().getAllPortsStat(actualNodeRef);
+                    waitingForNotification();
+                    break;
+                case QUEUE_STATS:
+                    LOG.trace("STAT-MANAGER-collecting QUEUE-STATS for NodeRef {}", actualNodeRef);
+                    manager.getRpcMsgManager().getAllQueueStat(actualNodeRef);
+                    waitingForNotification();
+                    break;
+                case TABLE_STATS:
+                    LOG.trace("STAT-MANAGER-collecting TABLE-STATS for NodeRef {}", actualNodeRef);
+                    manager.getRpcMsgManager().getAllTablesStat(actualNodeRef);
+                    waitingForNotification();
+                    break;
+                case GROUP_STATS:
+                    LOG.trace("STAT-MANAGER-collecting GROUP-STATS for NodeRef {}", actualNodeRef);
+                    manager.getRpcMsgManager().getGroupFeaturesStat(actualNodeRef);
+                    waitingForNotification();
+                    manager.getRpcMsgManager().getAllGroupsConfStats(actualNodeRef);
+                    waitingForNotification();
+                    manager.getRpcMsgManager().getAllGroupsStat(actualNodeRef);
+                    waitingForNotification();
+                    break;
+                case METER_STATS:
+                    LOG.trace("STAT-MANAGER-collecting METER-STATS for NodeRef {}", actualNodeRef);
+                    manager.getRpcMsgManager().getMeterFeaturesStat(actualNodeRef);
+                    waitingForNotification();
+                    manager.getRpcMsgManager().getAllMeterConfigStat(actualNodeRef);
+                    waitingForNotification();
+                    manager.getRpcMsgManager().getAllMetersStat(actualNodeRef);
+                    waitingForNotification();
+                    break;
+                case FLOW_STATS:
+                    LOG.trace("STAT-MANAGER-collecting FLOW-STATS-ALL_FLOWS for NodeRef {}", actualNodeRef);
+                    manager.getRpcMsgManager().getAllFlowsStat(actualNodeRef);
+                    waitingForNotification();
+                    LOG.trace("STAT-MANAGER-collecting FLOW-AGGREGATE-STATS for NodeRef {}", actualNodeRef);
+                    for (short i = 0; i < maxTables; i++) {
+                        final TableId tableId = new TableId(i);
+                        manager.getRpcMsgManager().getAggregateFlowStat(actualNodeRef, tableId);
+                    }
+                    break;
+                default:
+                    /* Exception for programmers in implementation cycle */
+                    throw new IllegalStateException("Not implemented ASK for " + statMarker);
+                }
+            }
+        }
+    }
+
+    private class StatNodeInfoHolder {
+        private final NodeRef nodeRef;
+        private final List<StatCapabTypes> statMarkers;
+        private final Short maxTables;
+
+        public StatNodeInfoHolder(final NodeRef nodeRef,
+                final List<StatCapabTypes> statMarkers, final Short maxTables) {
+            this.nodeRef = nodeRef;
+            this.maxTables = maxTables;
+            this.statMarkers = statMarkers;
+        }
+
+        public final NodeRef getNodeRef() {
+            return nodeRef;
+        }
+
+        public final List<StatCapabTypes> getStatMarkers() {
+            return statMarkers;
+        }
+
+        public final Short getMaxTables() {
+            return maxTables;
+        }
+    }
+
+    @Override
+    public boolean hasActiveNodes() {
+        return ( ! statNodeHolder.isEmpty());
+    }
+}
+
@@ -5,17 +5,17 @@
  * 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;
+package org.opendaylight.controller.md.statistics.manager.impl;
 
 import org.opendaylight.yangtools.yang.common.RpcError;
 
-final class RPCFailedException extends RuntimeException {
+import java.util.Collection;
+
+public final class StatRPCFailedException extends RuntimeException {
     private static final long serialVersionUID = 1L;
     private final Collection<RpcError> errors;
 
-    public RPCFailedException(final String message, final Collection<RpcError> errors) {
+    public StatRPCFailedException(final String message, final Collection<RpcError> errors) {
         super(message);
         this.errors = errors;
     }
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatRpcMsgManagerImpl.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatRpcMsgManagerImpl.java
new file mode 100644 (file)
index 0000000..8058554
--- /dev/null
@@ -0,0 +1,517 @@
+/**
+ * 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.impl;
+
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation;
+import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
+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.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder;
+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.OpendaylightFlowTableStatisticsService;
+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.GetAllGroupStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupFeaturesInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
+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.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetMeterFeaturesInputBuilder;
+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.OpendaylightPortStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+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.Preconditions;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.SettableFuture;
+
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager.impl
+ *
+ * StatRpcMsgManagerImpl
+ * Class register and provide all RPC Statistics Device Services and implement pre-defined
+ * wrapped methods for prepare easy access to RPC Statistics Device Services like getAllStatisticsFor...
+ *
+ * In next Class implement process for joining multipart messages.
+ * Class internally use two WeakHashMap and GuavaCache for holding values for joining multipart msg.
+ * One Weak map is used for holding all Multipart Messages and second is used for possible input
+ * Config/DS light-weight DataObject (DataObject contains only necessary identification fields as
+ * TableId, GroupId, MeterId or for flow Match, Priority, FlowCookie, TableId and FlowId ...
+ *
+ * @author avishnoi@in.ibm.com <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class StatRpcMsgManagerImpl implements StatRpcMsgManager {
+
+    private final static Logger LOG = LoggerFactory.getLogger(StatRpcMsgManagerImpl.class);
+
+    private final Cache<String, TransactionCacheContainer<? super TransactionAware>> txCache;
+
+    private final long maxLifeForRequest = 50; /* 50 second */
+    private final int queueCapacity = 5000;
+    private final StatisticsManager manager;
+
+    private final OpendaylightGroupStatisticsService groupStatsService;
+    private final OpendaylightMeterStatisticsService meterStatsService;
+    private final OpendaylightFlowStatisticsService flowStatsService;
+    private final OpendaylightPortStatisticsService portStatsService;
+    private final OpendaylightFlowTableStatisticsService flowTableStatsService;
+    private final OpendaylightQueueStatisticsService queueStatsService;
+
+    private BlockingQueue<RpcJobsQueue> statsRpcJobQueue;
+
+    private volatile boolean finishing = false;
+
+    public StatRpcMsgManagerImpl (final StatisticsManager manager,
+            final RpcConsumerRegistry rpcRegistry, final long minReqNetMonitInt) {
+        this.manager = Preconditions.checkNotNull(manager, "StatisticManager can not be null!");
+        Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !");
+        groupStatsService = Preconditions.checkNotNull(
+                rpcRegistry.getRpcService(OpendaylightGroupStatisticsService.class),
+                "OpendaylightGroupStatisticsService can not be null!");
+        meterStatsService = Preconditions.checkNotNull(
+                rpcRegistry.getRpcService(OpendaylightMeterStatisticsService.class),
+                "OpendaylightMeterStatisticsService can not be null!");
+        flowStatsService = Preconditions.checkNotNull(
+                rpcRegistry.getRpcService(OpendaylightFlowStatisticsService.class),
+                "OpendaylightFlowStatisticsService can not be null!");
+        portStatsService = Preconditions.checkNotNull(
+                rpcRegistry.getRpcService(OpendaylightPortStatisticsService.class),
+                "OpendaylightPortStatisticsService can not be null!");
+        flowTableStatsService = Preconditions.checkNotNull(
+                rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class),
+                "OpendaylightFlowTableStatisticsService can not be null!");
+        queueStatsService = Preconditions.checkNotNull(
+                rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class),
+                "OpendaylightQueueStatisticsService can not be null!");
+
+        statsRpcJobQueue = new LinkedBlockingQueue<>(queueCapacity);
+        txCache = CacheBuilder.newBuilder().expireAfterWrite(maxLifeForRequest, TimeUnit.SECONDS)
+                .maximumSize(10000).build();
+    }
+
+    @Override
+    public void close() {
+        finishing = true;
+        statsRpcJobQueue = null;
+    }
+
+    @Override
+    public void run() {
+         /* Neverending cyle - wait for finishing */
+        while ( ! finishing) {
+            try {
+                statsRpcJobQueue.take().call();
+            }
+            catch (final Exception e) {
+                LOG.warn("Stat Element RPC executor fail!", e);
+            }
+        }
+        // Drain all rpcCall, making sure any blocked threads are unblocked
+        while ( ! statsRpcJobQueue.isEmpty()) {
+            statsRpcJobQueue.poll();
+        }
+    }
+
+    private void addGetAllStatJob(final RpcJobsQueue getAllStatJob) {
+        final boolean success = statsRpcJobQueue.offer(getAllStatJob);
+        if ( ! success) {
+            LOG.warn("Put RPC request getAllStat fail! Queue is full.");
+        }
+    }
+
+    private void addStatJob(final RpcJobsQueue getStatJob) {
+        final boolean success = statsRpcJobQueue.offer(getStatJob);
+        if ( ! success) {
+            LOG.debug("Put RPC request for getStat fail! Queue is full.");
+        }
+    }
+
+    @Override
+    public <T extends TransactionAware, D extends DataObject> void registrationRpcFutureCallBack(
+            final Future<RpcResult<T>> future, final D inputObj, final NodeRef nodeRef) {
+
+        Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future),
+                new FutureCallback<RpcResult<? extends TransactionAware>>() {
+
+            @Override
+            public void onSuccess(final RpcResult<? extends TransactionAware> result) {
+                final TransactionId id = result.getResult().getTransactionId();
+                if (id == null) {
+                    LOG.warn("No protocol support");
+                } else {
+                    final NodeKey nodeKey = nodeRef.getValue().firstKeyOf(Node.class, NodeKey.class);
+                    final String cacheKey = buildCacheKey(id, nodeKey.getId());
+                    final TransactionCacheContainer<? super TransactionAware> container =
+                            new TransactionCacheContainerImpl<>(id, inputObj, nodeKey.getId());
+                    txCache.put(cacheKey, container);
+                }
+            }
+
+            @Override
+            public void onFailure(final Throwable t) {
+                LOG.warn("Response Registration for Statistics RPC call fail!", t);
+            }
+
+        });
+    }
+
+    private String buildCacheKey(final TransactionId id, final NodeId nodeId) {
+        return String.valueOf(id.getValue()) + "-" + nodeId.getValue();
+    }
+
+    @Override
+    public Future<Optional<TransactionCacheContainer<?>>> getTransactionCacheContainer(
+            final TransactionId id, final NodeId nodeId) {
+        Preconditions.checkArgument(id != null, "TransactionId can not be null!");
+        Preconditions.checkArgument(nodeId != null, "NodeId can not be null!");
+
+        final String key = buildCacheKey(id, nodeId);
+        final SettableFuture<Optional<TransactionCacheContainer<?>>> result = SettableFuture.create();
+
+        final RpcJobsQueue getTransactionCacheContainer = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                final Optional<TransactionCacheContainer<?>> resultContainer =
+                        Optional.<TransactionCacheContainer<?>> fromNullable(txCache.getIfPresent(key));
+                if (resultContainer.isPresent()) {
+                    txCache.invalidate(key);
+                }
+                result.set(resultContainer);
+                return null;
+            }
+        };
+        addStatJob(getTransactionCacheContainer);
+        return result;
+    }
+
+    @Override
+    public Future<Boolean> isExpectedStatistics(final TransactionId id, final NodeId nodeId) {
+        Preconditions.checkArgument(id != null, "TransactionId can not be null!");
+        Preconditions.checkArgument(nodeId != null, "NodeId can not be null!");
+
+        final String key = buildCacheKey(id, nodeId);
+        final SettableFuture<Boolean> checkStatId = SettableFuture.create();
+
+        final RpcJobsQueue isExpecedStatistics = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                final Optional<TransactionCacheContainer<?>> result =
+                        Optional.<TransactionCacheContainer<?>> fromNullable(txCache.getIfPresent(key));
+                checkStatId.set(Boolean.valueOf(result.isPresent()));
+                return null;
+            }
+        };
+        addStatJob(isExpecedStatistics);
+        return checkStatId;
+    }
+
+    @Override
+    public void addNotification(final TransactionAware notification, final NodeId nodeId) {
+        Preconditions.checkArgument(notification != null, "TransactionAware can not be null!");
+        Preconditions.checkArgument(nodeId != null, "NodeId can not be null!");
+
+        final RpcJobsQueue addNotification = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                final TransactionId txId = notification.getTransactionId();
+                final String key = buildCacheKey(txId, nodeId);
+                final TransactionCacheContainer<? super TransactionAware> container = (txCache.getIfPresent(key));
+                if (container != null) {
+                    container.addNotif(notification);
+                }
+                return null;
+            }
+        };
+        addStatJob(addNotification);
+    }
+
+    @Override
+    public void getAllGroupsStat(final NodeRef nodeRef) {
+        Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!");
+        final RpcJobsQueue getAllGroupStat = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                final GetAllGroupStatisticsInputBuilder builder =
+                        new GetAllGroupStatisticsInputBuilder();
+                builder.setNode(nodeRef);
+                registrationRpcFutureCallBack(groupStatsService
+                        .getAllGroupStatistics(builder.build()), null, nodeRef);
+                return null;
+            }
+        };
+        addGetAllStatJob(getAllGroupStat);
+    }
+
+    @Override
+    public void getAllMetersStat(final NodeRef nodeRef) {
+        Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!");
+        final RpcJobsQueue getAllMeterStat = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                final GetAllMeterStatisticsInputBuilder builder =
+                        new GetAllMeterStatisticsInputBuilder();
+                builder.setNode(nodeRef);
+                registrationRpcFutureCallBack(meterStatsService
+                        .getAllMeterStatistics(builder.build()), null, nodeRef);
+                return null;
+            }
+        };
+        addGetAllStatJob(getAllMeterStat);
+    }
+
+    @Override
+    public void getAllFlowsStat(final NodeRef nodeRef) {
+        Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!");
+        final RpcJobsQueue getAllFlowStat = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder builder =
+                        new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder();
+                builder.setNode(nodeRef);
+                registrationRpcFutureCallBack(flowStatsService
+                        .getAllFlowsStatisticsFromAllFlowTables(builder.build()), null, nodeRef);
+                return null;
+            }
+        };
+        addGetAllStatJob(getAllFlowStat);
+    }
+
+    @Override
+    public void getAggregateFlowStat(final NodeRef nodeRef, final TableId tableId) {
+
+        manager.enqueue(new StatDataStoreOperation() {
+
+            @Override
+            public void applyOperation(final ReadWriteTransaction tx) {
+                final RpcJobsQueue getAggregateFlowStat = new RpcJobsQueue() {
+                    @Override
+                    public Void call() throws Exception {
+                        final GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder builder =
+                                new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder();
+                        builder.setNode(nodeRef);
+                        builder.setTableId(tableId);
+
+                        final TableBuilder tbuilder = new TableBuilder();
+                        tbuilder.setId(tableId.getValue());
+                        tbuilder.setKey(new TableKey(tableId.getValue()));
+                        registrationRpcFutureCallBack(flowStatsService
+                                .getAggregateFlowStatisticsFromFlowTableForAllFlows(builder.build()), tbuilder.build(), nodeRef);
+                        return null;
+                    }
+                };
+                addGetAllStatJob(getAggregateFlowStat);
+            }
+        });
+    }
+
+    @Override
+    public void getAllPortsStat(final NodeRef nodeRef) {
+        Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!");
+        final RpcJobsQueue getAllPortsStat = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                final GetAllNodeConnectorsStatisticsInputBuilder builder =
+                        new GetAllNodeConnectorsStatisticsInputBuilder();
+                builder.setNode(nodeRef);
+                registrationRpcFutureCallBack(portStatsService
+                        .getAllNodeConnectorsStatistics(builder.build()), null, nodeRef);
+                return null;
+            }
+        };
+        addGetAllStatJob(getAllPortsStat);
+    }
+
+    @Override
+    public void getAllTablesStat(final NodeRef nodeRef) {
+        Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!");
+        final RpcJobsQueue getAllTableStat = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                final GetFlowTablesStatisticsInputBuilder builder =
+                        new GetFlowTablesStatisticsInputBuilder();
+                builder.setNode(nodeRef);
+                registrationRpcFutureCallBack(flowTableStatsService
+                        .getFlowTablesStatistics(builder.build()), null, nodeRef);
+                return null;
+            }
+        };
+        addGetAllStatJob(getAllTableStat);
+    }
+
+    @Override
+    public void getAllQueueStat(final NodeRef nodeRef) {
+        Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!");
+        final RpcJobsQueue getAllQueueStat = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                final GetAllQueuesStatisticsFromAllPortsInputBuilder builder =
+                        new GetAllQueuesStatisticsFromAllPortsInputBuilder();
+                builder.setNode(nodeRef);
+                registrationRpcFutureCallBack(queueStatsService
+                        .getAllQueuesStatisticsFromAllPorts(builder.build()), null, nodeRef);
+                return null;
+            }
+        };
+        addGetAllStatJob(getAllQueueStat);
+    }
+
+    @Override
+    public void getAllMeterConfigStat(final NodeRef nodeRef) {
+        Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!");
+        final RpcJobsQueue qetAllMeterConfStat = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                final GetAllMeterConfigStatisticsInputBuilder builder =
+                        new GetAllMeterConfigStatisticsInputBuilder();
+                builder.setNode(nodeRef);
+                registrationRpcFutureCallBack(meterStatsService
+                        .getAllMeterConfigStatistics(builder.build()), null, nodeRef);
+                return null;
+            }
+        };
+        addGetAllStatJob(qetAllMeterConfStat);
+    }
+
+    @Override
+    public void getGroupFeaturesStat(final NodeRef nodeRef) {
+        Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!");
+        final RpcJobsQueue getGroupFeaturesStat = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                /* RPC input */
+                final GetGroupFeaturesInputBuilder input = new GetGroupFeaturesInputBuilder();
+                input.setNode(nodeRef);
+                registrationRpcFutureCallBack(groupStatsService.getGroupFeatures(input.build()), null, nodeRef);
+                return null;
+            }
+        };
+        addStatJob(getGroupFeaturesStat);
+    }
+
+    @Override
+    public void getMeterFeaturesStat(final NodeRef nodeRef) {
+        Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!");
+        final RpcJobsQueue getMeterFeaturesStat = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                /* RPC input */
+                final GetMeterFeaturesInputBuilder input = new GetMeterFeaturesInputBuilder();
+                input.setNode(nodeRef);
+                registrationRpcFutureCallBack(meterStatsService.getMeterFeatures(input.build()), null, nodeRef);
+                return null;
+            }
+        };
+        addStatJob(getMeterFeaturesStat);
+    }
+
+    @Override
+    public void getAllGroupsConfStats(final NodeRef nodeRef) {
+        Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!");
+        final RpcJobsQueue getAllGropConfStat = new RpcJobsQueue() {
+
+            @Override
+            public Void call() throws Exception {
+                Preconditions.checkArgument(nodeRef != null, "NodeRef can not be null!");
+                final GetGroupDescriptionInputBuilder builder =
+                        new GetGroupDescriptionInputBuilder();
+                builder.setNode(nodeRef);
+                registrationRpcFutureCallBack(groupStatsService
+                        .getGroupDescription(builder.build()), null, nodeRef);
+
+                return null;
+            }
+        };
+        addGetAllStatJob(getAllGropConfStat);
+    }
+
+    public class TransactionCacheContainerImpl<T extends TransactionAware> implements TransactionCacheContainer<T> {
+
+        private final TransactionId id;
+        private final NodeId nId;
+        private final List<T> notifications;
+        private final Optional<? extends DataObject> confInput;
+
+        public <D extends DataObject> TransactionCacheContainerImpl (final TransactionId id, final D input, final NodeId nodeId) {
+            this.id = Preconditions.checkNotNull(id, "TransactionId can not be null!");
+            notifications = new CopyOnWriteArrayList<T>();
+            confInput = Optional.fromNullable(input);
+            nId = nodeId;
+        }
+
+        @Override
+        public void addNotif(final T notif) {
+            notifications.add(notif);
+        }
+
+        @Override
+        public TransactionId getId() {
+            return id;
+        }
+
+        @Override
+        public NodeId getNodeId() {
+            return nId;
+        }
+
+        @Override
+        public List<T> getNotifications() {
+            return notifications;
+        }
+
+        @Override
+        public Optional<? extends DataObject> getConfInput() {
+            return confInput;
+        }
+    }
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatisticsManagerImpl.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/impl/StatisticsManagerImpl.java
new file mode 100644 (file)
index 0000000..8430549
--- /dev/null
@@ -0,0 +1,358 @@
+/**
+ * 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.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.ThreadFactory;
+
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.statistics.manager.StatListeningCommiter;
+import org.opendaylight.controller.md.statistics.manager.StatNodeRegistration;
+import org.opendaylight.controller.md.statistics.manager.StatNotifyCommiter;
+import org.opendaylight.controller.md.statistics.manager.StatPermCollector;
+import org.opendaylight.controller.md.statistics.manager.StatPermCollector.StatCapabTypes;
+import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
+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.OpendaylightFlowStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
+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.OpendaylightGroupStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener;
+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.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+/**
+* statistics-manager
+* org.opendaylight.controller.md.statistics.manager.impl
+*
+* StatisticsManagerImpl
+* It represent a central point for whole module. Implementation
+* {@link StatisticsManager} registers all Operation/DS {@link StatNotifyCommiter} and
+* Config/DS {@StatListeningCommiter}, as well as {@link StatPermCollector}
+* for statistic collecting and {@link StatRpcMsgManager} as Device RPCs provider.
+* In next, StatisticsManager provides all DS contact Transaction services.
+*
+* @author avishnoi@in.ibm.com <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+*
+*/
+public class StatisticsManagerImpl implements StatisticsManager, Runnable {
+
+   private final static Logger LOG = LoggerFactory.getLogger(StatisticsManagerImpl.class);
+
+   private static final int QUEUE_DEPTH = 500;
+   private static final int MAX_BATCH = 1;
+
+   private final BlockingQueue<StatDataStoreOperation> dataStoreOperQueue = new LinkedBlockingDeque<>(QUEUE_DEPTH);
+
+   private final DataBroker dataBroker;
+   private final int maxNodesForCollectors;
+   private long minReqNetMonitInt;
+   private final ExecutorService statRpcMsgManagerExecutor;
+   private final ExecutorService statDataStoreOperationServ;
+   private StatRpcMsgManager rpcMsgManager;
+   private List<StatPermCollector> statCollectors;
+   private final Object statCollectorLock = new Object();
+   private BindingTransactionChain txChain;
+   private volatile boolean finishing = false;
+
+   private StatNodeRegistration nodeRegistrator;
+   private StatListeningCommiter<Flow, OpendaylightFlowStatisticsListener> flowListeningCommiter;
+   private StatListeningCommiter<Meter, OpendaylightMeterStatisticsListener> meterListeningCommiter;
+   private StatListeningCommiter<Group, OpendaylightGroupStatisticsListener> groupListeningCommiter;
+   private StatListeningCommiter<Queue, OpendaylightQueueStatisticsListener> queueNotifyCommiter;
+   private StatNotifyCommiter<OpendaylightFlowTableStatisticsListener> tableNotifCommiter;
+   private StatNotifyCommiter<OpendaylightPortStatisticsListener> portNotifyCommiter;
+
+   public StatisticsManagerImpl (final DataBroker dataBroker, final int maxNodesForCollector) {
+       this.dataBroker = Preconditions.checkNotNull(dataBroker, "DataBroker can not be null!");
+       ThreadFactory threadFact;
+       threadFact = new ThreadFactoryBuilder().setNameFormat("odl-stat-rpc-oper-thread-%d").build();
+       statRpcMsgManagerExecutor = Executors.newSingleThreadExecutor(threadFact);
+       threadFact = new ThreadFactoryBuilder().setNameFormat("odl-stat-ds-oper-thread-%d").build();
+       statDataStoreOperationServ = Executors.newSingleThreadExecutor(threadFact);
+       maxNodesForCollectors = maxNodesForCollector;
+       txChain =  dataBroker.createTransactionChain(this);
+   }
+
+   @Override
+   public void start(final NotificationProviderService notifService,
+           final RpcConsumerRegistry rpcRegistry, final long minReqNetMonitInt) {
+       Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !");
+       this.minReqNetMonitInt = minReqNetMonitInt;
+       rpcMsgManager = new StatRpcMsgManagerImpl(this, rpcRegistry, minReqNetMonitInt);
+       statCollectors = Collections.emptyList();
+       nodeRegistrator = new StatNodeRegistrationImpl(this, dataBroker, notifService);
+       flowListeningCommiter = new StatListenCommitFlow(this, dataBroker, notifService);
+       meterListeningCommiter = new StatListenCommitMeter(this, dataBroker, notifService);
+       groupListeningCommiter = new StatListenCommitGroup(this, dataBroker, notifService);
+       tableNotifCommiter = new StatNotifyCommitTable(this, notifService);
+       portNotifyCommiter = new StatNotifyCommitPort(this, notifService);
+       queueNotifyCommiter = new StatListenCommitQueue(this, dataBroker, notifService);
+
+       statRpcMsgManagerExecutor.execute(rpcMsgManager);
+       statDataStoreOperationServ.execute(this);
+       LOG.info("Statistics Manager started successfully!");
+   }
+
+   @Override
+   public void close() throws Exception {
+       finishing = true;
+       if (nodeRegistrator != null) {
+           nodeRegistrator.close();
+           nodeRegistrator = null;
+       }
+       if (flowListeningCommiter != null) {
+           flowListeningCommiter.close();
+           flowListeningCommiter = null;
+       }
+       if (meterListeningCommiter != null) {
+           meterListeningCommiter.close();
+           meterListeningCommiter = null;
+       }
+       if (groupListeningCommiter != null) {
+           groupListeningCommiter.close();
+           groupListeningCommiter = null;
+       }
+       if (tableNotifCommiter != null) {
+           tableNotifCommiter.close();
+           tableNotifCommiter = null;
+       }
+       if (portNotifyCommiter != null) {
+           portNotifyCommiter.close();
+           portNotifyCommiter = null;
+       }
+       if (queueNotifyCommiter != null) {
+           queueNotifyCommiter.close();
+           queueNotifyCommiter = null;
+       }
+       if (statCollectors != null) {
+           for (StatPermCollector collector : statCollectors) {
+               collector.close();
+               collector = null;
+           }
+           statCollectors = null;
+       }
+       if (rpcMsgManager != null) {
+           rpcMsgManager.close();
+           rpcMsgManager = null;
+       }
+       statRpcMsgManagerExecutor.shutdown();
+       statDataStoreOperationServ.shutdown();
+       if (txChain != null) {
+           txChain.close();
+           txChain = null;
+       }
+   }
+
+   @Override
+   public void enqueue(final StatDataStoreOperation op) {
+       // we don't need to block anything - next statistics come soon
+       final boolean success = dataStoreOperQueue.offer(op);
+       if ( ! success) {
+           LOG.debug("Stat DS/Operational submiter Queue is full!");
+       }
+   }
+
+   @Override
+   public void run() {
+       /* Neverending cyle - wait for finishing */
+       while ( ! finishing) {
+           try {
+               StatDataStoreOperation op = dataStoreOperQueue.take();
+               final ReadWriteTransaction tx = txChain.newReadWriteTransaction();
+               LOG.trace("New operations available, starting transaction {}", tx.getIdentifier());
+
+               int ops = 0;
+               do {
+                   op.applyOperation(tx);
+
+                   ops++;
+                   if (ops < MAX_BATCH) {
+                       op = dataStoreOperQueue.poll();
+                   } else {
+                       op = null;
+                   }
+               } while (op != null);
+
+               LOG.trace("Processed {} operations, submitting transaction {}", ops, tx.getIdentifier());
+
+               try {
+                   tx.submit().checkedGet();
+               } catch (final TransactionCommitFailedException e) {
+                   LOG.warn("Stat DataStoreOperation unexpected State!", e);
+                   txChain.close();
+                   txChain = dataBroker.createTransactionChain(StatisticsManagerImpl.this);
+                   cleanDataStoreOperQueue();
+               }
+           }
+           catch (final IllegalStateException e) {
+               LOG.warn("Stat DataStoreOperation unexpected State!", e);
+           }
+           catch (final InterruptedException e) {
+               LOG.warn("Stat Manager DS Operation thread interupted!", e);
+               finishing = true;
+           }
+           catch (final Exception e) {
+               LOG.warn("Stat DataStore Operation executor fail!", e);
+           }
+       }
+       // Drain all events, making sure any blocked threads are unblocked
+       cleanDataStoreOperQueue();
+   }
+
+   private void cleanDataStoreOperQueue() {
+       // Drain all events, making sure any blocked threads are unblocked
+       while (! dataStoreOperQueue.isEmpty()) {
+           dataStoreOperQueue.poll();
+       }
+   }
+
+   @Override
+   public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction,
+           final Throwable cause) {
+       LOG.warn("Failed to export Flow Capable Statistics, Transaction {} failed.",transaction.getIdentifier(),cause);
+       txChain.close();
+       txChain = dataBroker.createTransactionChain(StatisticsManagerImpl.this);
+       cleanDataStoreOperQueue();
+   }
+
+   @Override
+   public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
+       // NOOP
+   }
+
+   @Override
+   public boolean isProvidedFlowNodeActive(final InstanceIdentifier<Node> nodeIdent) {
+       for (final StatPermCollector collector : statCollectors) {
+           if (collector.isProvidedFlowNodeActive(nodeIdent)) {
+               return true;
+           }
+       }
+       return false;
+   }
+
+   @Override
+   public void collectNextStatistics(final InstanceIdentifier<Node> nodeIdent) {
+       for (final StatPermCollector collector : statCollectors) {
+           if (collector.isProvidedFlowNodeActive(nodeIdent)) {
+               collector.collectNextStatistics();
+           }
+       }
+   }
+
+   @Override
+   public void connectedNodeRegistration(final InstanceIdentifier<Node> nodeIdent,
+           final List<StatCapabTypes> statTypes, final Short nrOfSwitchTables) {
+       for (final StatPermCollector collector : statCollectors) {
+           if (collector.connectedNodeRegistration(nodeIdent, statTypes, nrOfSwitchTables)) {
+               return;
+           }
+       }
+       synchronized (statCollectorLock) {
+           for (final StatPermCollector collector : statCollectors) {
+               if (collector.connectedNodeRegistration(nodeIdent, statTypes, nrOfSwitchTables)) {
+                   return;
+               }
+           }
+           final StatPermCollectorImpl newCollector = new StatPermCollectorImpl(this,
+                   minReqNetMonitInt, statCollectors.size() + 1, maxNodesForCollectors);
+           final List<StatPermCollector> statCollectorsNew = new ArrayList<>(statCollectors);
+           newCollector.connectedNodeRegistration(nodeIdent, statTypes, nrOfSwitchTables);
+           statCollectorsNew.add(newCollector);
+           statCollectors = Collections.unmodifiableList(statCollectorsNew);
+       }
+   }
+
+   @Override
+   public void disconnectedNodeUnregistration(final InstanceIdentifier<Node> nodeIdent) {
+       for (final StatPermCollector collector : statCollectors) {
+           if (collector.disconnectedNodeUnregistration(nodeIdent)) {
+               if ( ! collector.hasActiveNodes()) {
+                   synchronized (statCollectorLock) {
+                       if (collector.hasActiveNodes()) {
+                           return;
+                       }
+                       final List<StatPermCollector> newStatColl =
+                               new ArrayList<>(statCollectors);
+                       newStatColl.remove(collector);
+                       statCollectors = Collections.unmodifiableList(newStatColl);
+                   }
+               }
+               return;
+           }
+       }
+       LOG.debug("Node {} has not removed.", nodeIdent);
+   }
+
+   /* Getter internal Statistic Manager Job Classes */
+   @Override
+   public StatRpcMsgManager getRpcMsgManager() {
+       return rpcMsgManager;
+   }
+
+   @Override
+   public StatNodeRegistration getNodeRegistrator() {
+       return nodeRegistrator;
+   }
+
+   @Override
+   public StatListeningCommiter<Flow, OpendaylightFlowStatisticsListener> getFlowListenComit() {
+       return flowListeningCommiter;
+   }
+
+   @Override
+   public StatListeningCommiter<Meter, OpendaylightMeterStatisticsListener> getMeterListenCommit() {
+       return meterListeningCommiter;
+   }
+
+   @Override
+   public StatListeningCommiter<Group, OpendaylightGroupStatisticsListener> getGroupListenCommit() {
+       return groupListeningCommiter;
+   }
+
+   @Override
+   public StatListeningCommiter<Queue, OpendaylightQueueStatisticsListener> getQueueNotifyCommit() {
+       return queueNotifyCommiter;
+   }
+
+
+   @Override
+   public StatNotifyCommiter<OpendaylightFlowTableStatisticsListener> getTableNotifCommit() {
+       return tableNotifCommiter;
+   }
+
+   @Override
+   public StatNotifyCommiter<OpendaylightPortStatisticsListener> getPortNotifyCommit() {
+       return portNotifyCommiter;
+   }
+}
+
@@ -5,15 +5,14 @@
  * 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;
+package org.opendaylight.controller.md.statistics.manager.impl.helper;
 
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.net.InetAddresses;
 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.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
-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;
 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.MacAddressFilter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
@@ -22,19 +21,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026
 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);
+public final class FlowComparator {
+    private final static Logger LOG = LoggerFactory.getLogger(FlowComparator.class);
 
     private FlowComparator() {
-
+        throw new UnsupportedOperationException("Utilities class should not be instantiated");
     }
 
-    public static boolean flowEquals(Flow statsFlow, Flow storedFlow) {
+    public static boolean flowEquals(final Flow statsFlow, final Flow storedFlow) {
         if (statsFlow == null || storedFlow == null) {
             return false;
         }
@@ -93,7 +90,7 @@ final class FlowComparator {
      * @param storedFlow
      * @return
      */
-    public static boolean matchEquals(Match statsFlow, Match storedFlow) {
+    public static boolean matchEquals(final Match statsFlow, final Match storedFlow) {
         if (statsFlow == storedFlow) {
             return true;
         }
@@ -194,9 +191,9 @@ final class FlowComparator {
      * statistic data, openflow driver library returns AA:BB:CC:DD:EE:FF and default eqauls fails here.
      */
     @VisibleForTesting
-    static boolean ethernetMatchEquals(EthernetMatch statsEthernetMatch, EthernetMatch storedEthernetMatch){
+    static boolean ethernetMatchEquals(final EthernetMatch statsEthernetMatch, final EthernetMatch storedEthernetMatch){
         boolean verdict = true;
-        Boolean checkNullValues = checkNullValues(statsEthernetMatch, storedEthernetMatch);
+        final Boolean checkNullValues = checkNullValues(statsEthernetMatch, storedEthernetMatch);
         if (checkNullValues != null) {
             verdict = checkNullValues;
         } else {
@@ -219,10 +216,10 @@ final class FlowComparator {
         return verdict;
     }
 
-    private static boolean ethernetMatchFieldsEquals(MacAddressFilter statsEthernetMatchFields,
-                                                        MacAddressFilter storedEthernetMatchFields){
+    private static boolean ethernetMatchFieldsEquals(final MacAddressFilter statsEthernetMatchFields,
+                                                        final MacAddressFilter storedEthernetMatchFields){
         boolean verdict = true;
-        Boolean checkNullValues = checkNullValues(statsEthernetMatchFields, storedEthernetMatchFields);
+        final Boolean checkNullValues = checkNullValues(statsEthernetMatchFields, storedEthernetMatchFields);
         if (checkNullValues != null) {
             verdict = checkNullValues;
         } else {
@@ -236,9 +233,9 @@ final class FlowComparator {
         return verdict;
     }
 
-    private static boolean macAddressEquals(MacAddress statsMacAddress, MacAddress storedMacAddress){
+    private static boolean macAddressEquals(final MacAddress statsMacAddress, final MacAddress storedMacAddress){
         boolean verdict = true;
-        Boolean checkNullValues = checkNullValues(statsMacAddress, storedMacAddress);
+        final Boolean checkNullValues = checkNullValues(statsMacAddress, storedMacAddress);
         if (checkNullValues != null) {
             verdict = checkNullValues;
         } else {
@@ -248,11 +245,11 @@ final class FlowComparator {
     }
 
     @VisibleForTesting
-    static boolean layer3MatchEquals(Layer3Match statsLayer3Match, Layer3Match storedLayer3Match){
+    static boolean layer3MatchEquals(final Layer3Match statsLayer3Match, final Layer3Match storedLayer3Match){
         boolean verdict = true;
         if(statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match){
-            Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match;
-            Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match;
+            final Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match;
+            final Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match;
 
             if (verdict) {
                 verdict = compareNullSafe(
@@ -263,7 +260,7 @@ final class FlowComparator {
                         statsIpv4Match.getIpv4Source(), storedIpv4Match.getIpv4Source());
             }
         } else {
-            Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match);
+            final Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match);
             if (nullCheckOut != null) {
                 verdict = nullCheckOut;
             } else {
@@ -274,9 +271,9 @@ final class FlowComparator {
         return verdict;
     }
 
-    private static boolean compareNullSafe(Ipv4Prefix statsIpv4, Ipv4Prefix storedIpv4) {
+    private static boolean compareNullSafe(final Ipv4Prefix statsIpv4, final Ipv4Prefix storedIpv4) {
         boolean verdict = true;
-        Boolean checkDestNullValuesOut = checkNullValues(storedIpv4, statsIpv4);
+        final Boolean checkDestNullValuesOut = checkNullValues(storedIpv4, statsIpv4);
         if (checkDestNullValuesOut != null) {
             verdict = checkDestNullValuesOut;
         } else if(!IpAddressEquals(statsIpv4, storedIpv4)){
@@ -286,7 +283,7 @@ final class FlowComparator {
         return verdict;
     }
 
-    private static Boolean checkNullValues(Object v1, Object v2) {
+    private static Boolean checkNullValues(final Object v1, final Object v2) {
         Boolean verdict = null;
         if (v1 == null && v2 != null) {
             verdict = Boolean.FALSE;
@@ -306,9 +303,9 @@ final class FlowComparator {
      * @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());
+    private static boolean IpAddressEquals(final Ipv4Prefix statsIpAddress, final Ipv4Prefix storedIpAddress) {
+        final IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue());
+        final IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue());
 
         if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){
             return true;
@@ -319,11 +316,11 @@ final class FlowComparator {
         return false;
     }
 
-    private static boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
+    private static boolean IpAndMaskBasedMatch(final IntegerIpAddress statsIpAddressInt,final IntegerIpAddress storedIpAddressInt){
         return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) ==  (storedIpAddressInt.getIp() & storedIpAddressInt.getMask()));
     }
 
-    private static boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
+    private static boolean IpBasedMatch(final IntegerIpAddress statsIpAddressInt,final IntegerIpAddress storedIpAddressInt){
         return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp());
     }
 
@@ -331,10 +328,10 @@ final class FlowComparator {
      * Method return integer version of ip address. Converted int will be mask if
      * mask specified
      */
-    private static IntegerIpAddress StrIpToIntIp(String ipAddresss){
+    private static IntegerIpAddress StrIpToIntIp(final String ipAddresss){
 
-        String[] parts = ipAddresss.split("/");
-        String ip = parts[0];
+        final String[] parts = ipAddresss.split("/");
+        final String ip = parts[0];
         int prefix;
 
         if (parts.length < 2) {
@@ -344,20 +341,19 @@ final class FlowComparator {
         }
 
         IntegerIpAddress integerIpAddress = null;
-        try {
-            Inet4Address addr = (Inet4Address) InetAddress.getByName(ip);
-            byte[] addrBytes = addr.getAddress();
-            int ipInt = ((addrBytes[0] & 0xFF) << 24) |
+
+            final Inet4Address addr = ((Inet4Address) InetAddresses.forString(ip));
+            final byte[] addrBytes = addr.getAddress();
+            final int ipInt = ((addrBytes[0] & 0xFF) << 24) |
                     ((addrBytes[1] & 0xFF) << 16) |
                     ((addrBytes[2] & 0xFF) << 8)  |
                     ((addrBytes[3] & 0xFF) << 0);
 
-            int mask = 0xffffffff << 32 - prefix;
+            // FIXME: Is this valid?
+            final 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;
     }
@@ -365,7 +361,7 @@ final class FlowComparator {
     private static class IntegerIpAddress{
         int ip;
         int mask;
-        public IntegerIpAddress(int ip, int mask) {
+        public IntegerIpAddress(final int ip, final int mask) {
             this.ip = ip;
             this.mask = mask;
         }
diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerProvider.java b/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerProvider.java
new file mode 100644 (file)
index 0000000..6a01cd2
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * 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;
+
+/**
+ * statistics-manager
+ * org.opendaylight.controller.md.statistics.manager
+ *
+ *
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Sep 6, 2014
+ */
+public class StatisticsManagerProvider {
+
+    private final StatisticsManagerActivator activator;
+
+    public StatisticsManagerProvider(final StatisticsManagerActivator activator) {
+        this.activator = activator;
+    }
+
+    /**
+     * Method provides Initialized {@link StatisticsManager}
+     * from {@link StatisticsManagerActivator} for all tests
+     * suites;
+     *
+     * @return
+     */
+    public StatisticsManager getStatisticsManager() {
+        return activator.getStatisticManager();
+    }
+}
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.md.statistics.manager;
+package org.opendaylight.controller.md.statistics.manager.impl.helper;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -35,7 +35,7 @@ public class StatisticsUpdateCommiterTest {
      */
     @Test
     public void testLayer3MatchEquals() {
-        String[][][] matchSeeds = new String[][][] {
+        final 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"}},
@@ -55,7 +55,7 @@ public class StatisticsUpdateCommiterTest {
                 {{null, null}, {null, null}},
         };
 
-        boolean[] matches = new boolean[] {
+        final boolean[] matches = new boolean[] {
                 true,
                 false,
                 false,
@@ -91,23 +91,23 @@ public class StatisticsUpdateCommiterTest {
      * @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);
+    private static void checkComparisonOfL3Match(final String m1Source, final String m1Destination,
+            final String m2Source, final String msDestination, final boolean matches) {
+        final Ipv4Match m1Layer3 = prepareIPv4Match(m1Source, m1Destination);
+        final 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) {
+        } catch (final 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();
+    private static Ipv4Match prepareIPv4Match(final String source, final String destination) {
+        final Ipv4MatchBuilder ipv4MatchBuilder = new Ipv4MatchBuilder();
         if (source != null) {
             ipv4MatchBuilder.setIpv4Source(new Ipv4Prefix(source));
         }
@@ -118,11 +118,11 @@ public class StatisticsUpdateCommiterTest {
         return ipv4MatchBuilder.build();
     }
     /**
-     * Test method for {@link org.opendaylight.controller.md.statistics.manager.FlowComparator#ethernetMatchEquals(EthernetMatch, EthernetMatch)
+     * Test method for {@link org.opendaylight.controller.md.statistics.manager.impl.helper.FlowComparator#ethernetMatchEquals(EthernetMatch, EthernetMatch)
      */
     @Test
     public void testEthernetMatchEquals() {
-        String[][][] ethernetMatchSeeds = new String[][][] {
+        final String[][][] ethernetMatchSeeds = new String[][][] {
                 {{"aa:bb:cc:dd:ee:ff", "ff:ff:ff:ff:ff:ff","0800"}, {"aa:bb:cc:dd:ee:ff", "ff:ff:ff:ff:ff:ff","0800"}},
                 {{"aa:bb:cc:dd:ee:ff", "ff:ff:ff:ff:ff:ff","0800"}, {"aa:bb:bc:cd:ee:ff", "ff:ff:ff:ff:ff:ff","0800"}},
                 {{"aa:bb:cc:dd:ee:ff", "ff:ff:ff:ff:ff:ff","0800"}, {"AA:BB:CC:DD:EE:FF", "ff:ff:ff:ff:ff:ff","0800"}},
@@ -143,7 +143,7 @@ public class StatisticsUpdateCommiterTest {
                 {{null, null,null}, {null, null,null}},
         };
 
-        boolean[] matches = new boolean[] {
+        final boolean[] matches = new boolean[] {
                 true,
                 false,
                 true,
@@ -176,24 +176,24 @@ public class StatisticsUpdateCommiterTest {
      * @param ethernetMatch1
      * @param ethernetMatch2
      */
-    private static void checkComparisonOfEthernetMatch(String macAddress1, String macAddressMask1,String etherType1,
-            String macAddress2, String macAddressMask2,String etherType2, boolean expectedResult) {
-        EthernetMatch ethernetMatch1 = prepareEthernetMatch(macAddress1, macAddressMask1,etherType1);
-        EthernetMatch ethernetMatch2 = prepareEthernetMatch(macAddress2, macAddressMask2,etherType2);
+    private static void checkComparisonOfEthernetMatch(final String macAddress1, final String macAddressMask1,final String etherType1,
+            final String macAddress2, final String macAddressMask2,final String etherType2, final boolean expectedResult) {
+        final EthernetMatch ethernetMatch1 = prepareEthernetMatch(macAddress1, macAddressMask1,etherType1);
+        final EthernetMatch ethernetMatch2 = prepareEthernetMatch(macAddress2, macAddressMask2,etherType2);
         boolean comparisonResult;
         try {
             comparisonResult = FlowComparator.ethernetMatchEquals(ethernetMatch1, ethernetMatch2);
             Assert.assertEquals("failed to compare: "+ethernetMatch1+" vs. "+ethernetMatch2,
                     expectedResult, comparisonResult);
-        } catch (Exception e) {
+        } catch (final Exception e) {
             LOG.error("failed to compare: {} vs. {}", ethernetMatch1, ethernetMatch2, e);
             Assert.fail(e.getMessage());
         }
     }
 
-    private static EthernetMatch prepareEthernetMatch(String macAddress, String macAddressMask, String etherType) {
-        EthernetMatchBuilder ethernetMatchBuilder = new EthernetMatchBuilder();
-        EthernetSourceBuilder ethernetSourceBuilder =  new EthernetSourceBuilder();
+    private static EthernetMatch prepareEthernetMatch(final String macAddress, final String macAddressMask, final String etherType) {
+        final EthernetMatchBuilder ethernetMatchBuilder = new EthernetMatchBuilder();
+        final EthernetSourceBuilder ethernetSourceBuilder =  new EthernetSourceBuilder();
         if (macAddress != null) {
             ethernetSourceBuilder.setAddress(new MacAddress(macAddress));
         }
@@ -201,7 +201,7 @@ public class StatisticsUpdateCommiterTest {
             ethernetSourceBuilder.setMask(new MacAddress(macAddressMask));
         }
         if(etherType != null){
-            EthernetTypeBuilder ethernetType = new EthernetTypeBuilder();
+            final EthernetTypeBuilder ethernetType = new EthernetTypeBuilder();
             ethernetType.setType(new EtherType(Long.parseLong(etherType,16)));
             ethernetMatchBuilder.setEthernetType(ethernetType.build());
         }
diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/FlowStatisticsTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/FlowStatisticsTest.java
new file mode 100644 (file)
index 0000000..7fc171c
--- /dev/null
@@ -0,0 +1,159 @@
+package test.mock;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManagerActivator;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityFlowStats;
+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.statistics.rev130819.FlowStatisticsData;
+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.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import test.mock.util.StatisticsManagerTest;
+
+import com.google.common.base.Optional;
+
+public class FlowStatisticsTest extends StatisticsManagerTest {
+    private final Object waitObject = new Object();
+
+//    @Test(timeout = 5000)
+    public void addedFlowOnDemandStatsTest() throws ExecutionException, InterruptedException, ReadFailedException {
+        final StatisticsManagerActivator activator = new StatisticsManagerActivator();
+        activator.onSessionInitiated(providerContext);
+
+        addFlowCapableNode(s1Key);
+
+        final Flow flow = getFlow();
+
+        final InstanceIdentifier<Flow> flowII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(flow.getTableId()))
+                .child(Flow.class, flow.getKey());
+        final InstanceIdentifier<Table> tableII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(flow.getTableId()));
+        final Table table = new TableBuilder().setKey(new TableKey(flow.getTableId())).setFlow(Collections.<Flow>emptyList()).build();
+
+        final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, tableII, table);
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, flowII, flow);
+        writeTx.put(LogicalDatastoreType.OPERATIONAL, tableII, table);
+        writeTx.put(LogicalDatastoreType.OPERATIONAL, flowII, flow);
+        assertCommit(writeTx.submit());
+
+        getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                flowII.augmentation(FlowStatisticsData.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE);
+
+        synchronized (waitObject) {
+            waitObject.wait();
+        }
+
+        final ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction();
+        final Optional<FlowStatisticsData> flowStatDataOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, flowII.augmentation(FlowStatisticsData.class))
+                .checkedGet();
+        assertTrue(flowStatDataOptional.isPresent());
+        assertEquals(COUNTER_64_TEST_VALUE, flowStatDataOptional.get().getFlowStatistics().getByteCount());
+
+    }
+
+//    @Test(timeout = 5000)
+    public void deletedFlowStatsRemovalTest() throws ExecutionException, InterruptedException, ReadFailedException {
+        final StatisticsManagerActivator activator = new StatisticsManagerActivator();
+        activator.onSessionInitiated(providerContext);
+
+        addFlowCapableNode(s1Key);
+
+        final Flow flow = getFlow();
+
+        final InstanceIdentifier<Flow> flowII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(flow.getTableId()))
+                .child(Flow.class, flow.getKey());
+        final InstanceIdentifier<Table> tableII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(flow.getTableId()));
+        final Table table = new TableBuilder().setKey(new TableKey(flow.getTableId())).setFlow(Collections.<Flow>emptyList()).build();
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, tableII, table);
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, flowII, flow);
+        writeTx.put(LogicalDatastoreType.OPERATIONAL, tableII, table);
+        writeTx.put(LogicalDatastoreType.OPERATIONAL, flowII, flow);
+
+        getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                flowII.augmentation(FlowStatisticsData.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE);
+
+        assertCommit(writeTx.submit());
+
+        synchronized (waitObject) {
+            waitObject.wait();
+        }
+
+        ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction();
+        Optional<Flow> flowStatDataOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, flowII).checkedGet();
+        assertTrue(flowStatDataOptional.isPresent());
+//        assertEquals(COUNTER_64_TEST_VALUE, flowStatDataOptional.get().getFlowStatistics().getByteCount());
+
+        writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.delete(LogicalDatastoreType.CONFIGURATION, flowII);
+        assertCommit(writeTx.submit());
+
+        readTx = getDataBroker().newReadOnlyTransaction();
+        flowStatDataOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, flowII).checkedGet();
+        assertFalse(flowStatDataOptional.isPresent());
+    }
+
+//    @Test(timeout = 23000)
+    public void getAllStatsWhenNodeIsConnectedTest() throws ExecutionException, InterruptedException, ReadFailedException {
+        final StatisticsManagerActivator activator = new StatisticsManagerActivator();
+        activator.onSessionInitiated(providerContext);
+
+        addFlowCapableNodeWithFeatures(s1Key, false, FlowFeatureCapabilityFlowStats.class);
+
+        final Flow flow = getFlow();
+
+        final InstanceIdentifier<Table> tableII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(flow.getTableId()));
+
+        getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                tableII.child(Flow.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE);
+
+        synchronized (waitObject) {
+            waitObject.wait();
+        }
+
+        final ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction();
+        final Optional<Table> tableOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class)
+                .child(Node.class, s1Key).augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(flow.getTableId()))).checkedGet();
+        assertTrue(tableOptional.isPresent());
+        final FlowStatisticsData flowStats = tableOptional.get().getFlow().get(0).getAugmentation(FlowStatisticsData.class);
+        assertTrue(flowStats != null);
+        assertEquals(COUNTER_64_TEST_VALUE, flowStats.getFlowStatistics().getByteCount());
+    }
+
+    public class ChangeListener implements DataChangeListener {
+
+        @Override
+        public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+            synchronized (waitObject) {
+                waitObject.notify();
+            }
+        }
+    }
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/GroupStatisticsTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/GroupStatisticsTest.java
new file mode 100644 (file)
index 0000000..7a61bf2
--- /dev/null
@@ -0,0 +1,151 @@
+package test.mock;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManagerActivator;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityGroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+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.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import test.mock.util.StatisticsManagerTest;
+
+import com.google.common.base.Optional;
+
+public class GroupStatisticsTest extends StatisticsManagerTest {
+    private final Object waitObject = new Object();
+
+//    @Test(timeout = 5000)
+    public void addedGroupOnDemandStatsTest() throws ExecutionException, InterruptedException, ReadFailedException {
+        final StatisticsManagerActivator activator = new StatisticsManagerActivator();
+        activator.onSessionInitiated(providerContext);
+
+        addFlowCapableNode(s1Key);
+
+        final Group group = getGroup();
+
+        final InstanceIdentifier<Group> groupII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Group.class, group.getKey());
+
+        final WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, groupII, group);
+        writeTx.put(LogicalDatastoreType.OPERATIONAL, groupII, group);
+        assertCommit(writeTx.submit());
+
+        getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                groupII.augmentation(NodeGroupStatistics.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE);
+
+        synchronized (waitObject) {
+            waitObject.wait();
+        }
+
+        final ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction();
+        final Optional<NodeGroupStatistics> groupOptional = readTx.read(LogicalDatastoreType.OPERATIONAL, groupII.augmentation(NodeGroupStatistics.class)).checkedGet();
+        assertTrue(groupOptional.isPresent());
+        assertEquals(COUNTER_64_TEST_VALUE, groupOptional.get().getGroupStatistics().getByteCount());
+    }
+
+//    @Test(timeout = 5000)
+    public void deletedGroupStasRemovalTest() throws ExecutionException, InterruptedException, ReadFailedException {
+        final StatisticsManagerActivator activator = new StatisticsManagerActivator();
+        activator.onSessionInitiated(providerContext);
+
+        addFlowCapableNode(s1Key);
+
+        final Group group = getGroup();
+        final InstanceIdentifier<Group> groupII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Group.class, group.getKey());
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, groupII, group);
+        writeTx.put(LogicalDatastoreType.OPERATIONAL, groupII, group);
+        assertCommit(writeTx.submit());
+
+        getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                groupII.augmentation(NodeGroupStatistics.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE);
+
+        synchronized (waitObject) {
+            waitObject.wait();
+        }
+
+        ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction();
+        Optional<NodeGroupStatistics> groupOptional = readTx.read(LogicalDatastoreType.OPERATIONAL,
+                groupII.augmentation(NodeGroupStatistics.class)).checkedGet();
+        assertTrue(groupOptional.isPresent());
+        assertEquals(COUNTER_64_TEST_VALUE, groupOptional.get().getGroupStatistics().getByteCount());
+
+        writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.delete(LogicalDatastoreType.CONFIGURATION, groupII);
+        assertCommit(writeTx.submit());
+
+        readTx = getDataBroker().newReadOnlyTransaction();
+        groupOptional = readTx.read(LogicalDatastoreType.OPERATIONAL,
+                groupII.augmentation(NodeGroupStatistics.class)).checkedGet();
+        assertFalse(groupOptional.isPresent());
+
+    }
+
+//    @Test(timeout = 23000)
+    public void getAllStatsFromConnectedNodeTest() throws ExecutionException, InterruptedException {
+        final StatisticsManagerActivator activator = new StatisticsManagerActivator();
+        activator.onSessionInitiated(providerContext);
+
+        addFlowCapableNodeWithFeatures(s1Key, false, FlowFeatureCapabilityGroupStats.class);
+
+        final InstanceIdentifier<Group> groupII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Group.class, getGroup().getKey());
+        getDataBroker().registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                groupII.augmentation(NodeGroupStatistics.class), new ChangeListener(), AsyncDataBroker.DataChangeScope.BASE);
+
+        synchronized (waitObject) {
+            waitObject.wait();
+        }
+
+        ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction();
+        final Optional<Group> optionalGroup = readTx.read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class)
+                .child(Node.class, s1Key).augmentation(FlowCapableNode.class)
+                .child(Group.class, getGroup().getKey())).get();
+
+        assertTrue(optionalGroup.isPresent());
+        assertTrue(optionalGroup.get().getAugmentation(NodeGroupDescStats.class) != null);
+        final NodeGroupStatistics groupStats = optionalGroup.get().getAugmentation(NodeGroupStatistics.class);
+        assertTrue(groupStats != null);
+        assertEquals(COUNTER_64_TEST_VALUE, groupStats.getGroupStatistics().getByteCount());
+
+        readTx = getDataBroker().newReadOnlyTransaction();
+        final Optional<GroupFeatures> optionalGroupFeatures = readTx.read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class)
+                .child(Node.class, s1Key).augmentation(NodeGroupFeatures.class).child(GroupFeatures.class)).get();
+        assertTrue(optionalGroupFeatures.isPresent());
+        assertEquals(1, optionalGroupFeatures.get().getMaxGroups().size());
+        assertEquals(MAX_GROUPS_TEST_VALUE, optionalGroupFeatures.get().getMaxGroups().get(0));
+    }
+
+    private class ChangeListener implements DataChangeListener {
+
+        @Override
+        public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+            synchronized (waitObject) {
+                waitObject.notify();
+            }
+        }
+    }
+}
+
diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/MeterStatisticsTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/test/mock/MeterStatisticsTest.java
new file mode 100644 (file)
index 0000000..a0f360c
--- /dev/null
@@ -0,0 +1,150 @@
+package test.mock;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.statistics.manager.StatisticsManagerActivator;
+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.inventory.rev130819.Nodes;
+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.NodeMeterFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeatures;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import test.mock.util.StatisticsManagerTest;
+
+import com.google.common.base.Optional;
+
+public class MeterStatisticsTest extends StatisticsManagerTest {
+    private final Object waitObject = new Object();
+
+//    @Test(timeout = 5000)
+    public void addedMeterOnDemandStatsTest() throws ExecutionException, InterruptedException, ReadFailedException {
+        final StatisticsManagerActivator activator = new StatisticsManagerActivator();
+        activator.onSessionInitiated(providerContext);
+
+        addFlowCapableNode(s1Key);
+
+        final Meter meter&nbs