Bug 5692 - Direct statistics RPC 44/38744/15
authorTomas Slusny <tomas.slusny@pantheon.sk>
Wed, 11 May 2016 17:03:01 +0000 (19:03 +0200)
committerTomas Slusny <tomas.slusny@pantheon.sk>
Thu, 19 May 2016 08:04:50 +0000 (10:04 +0200)
- Added new RPCs for direct gathering of statistics
  with optional flag of storing the statistics to DS/operational

Change-Id: I9d94595f9fb4f5e93f22958c64dd6cf3d4c19bcc
Signed-off-by: Tomas Slusny <tomas.slusny@pantheon.sk>
24 files changed:
model/model-flow-statistics/src/main/yang/opendaylight-direct-statistics.yang [new file with mode: 0644]
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceContext.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/TxFacade.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/TransactionChainManager.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/FlowsInTableService.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/AbstractDirectStatisticsService.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/FlowDirectStatisticsService.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/GroupDirectStatisticsService.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/MeterDirectStatisticsService.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/NodeConnectorDirectStatisticsService.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/OpendaylightDirectStatisticsServiceImpl.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/OpendaylightDirectStatisticsServiceProvider.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/QueueDirectStatisticsService.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtils.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/TransactionChainManagerTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/AbstractDirectStatisticsServiceTest.java [new file with mode: 0644]
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/FlowDirectStatisticsServiceTest.java [new file with mode: 0644]
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/GroupDirectStatisticsServiceTest.java [new file with mode: 0644]
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/MeterDirectStatisticsServiceTest.java [new file with mode: 0644]
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/NodeConnectorDirectStatisticsServiceTest.java [new file with mode: 0644]
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/OpendaylightDirectStatisticsServiceImplTest.java [new file with mode: 0644]
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/QueueDirectStatisticsServiceTest.java [new file with mode: 0644]
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/util/MdSalRegistrationUtilsTest.java

diff --git a/model/model-flow-statistics/src/main/yang/opendaylight-direct-statistics.yang b/model/model-flow-statistics/src/main/yang/opendaylight-direct-statistics.yang
new file mode 100644 (file)
index 0000000..e4037a4
--- /dev/null
@@ -0,0 +1,123 @@
+module opendaylight-direct-statistics {
+    namespace "urn:opendaylight:direct:statistics";
+    prefix directstat;
+
+    import yang-ext { prefix ext; revision-date "2013-07-09"; }
+    import ietf-inet-types { prefix inet; revision-date "2010-09-24"; }
+    import opendaylight-inventory { prefix inv; revision-date "2013-08-19"; }
+    import opendaylight-statistics-types { prefix stat-types; revision-date "2013-09-25"; }
+
+    import opendaylight-flow-types  { prefix flow-types;  revision-date "2013-10-26"; }
+    import opendaylight-group-types { prefix group-types; revision-date "2013-10-18"; }
+    import opendaylight-meter-types { prefix meter-types; revision-date "2013-09-18"; }
+    import opendaylight-queue-types { prefix queue-types; revision-date "2013-09-25"; }
+    import opendaylight-table-types { prefix table-types; revision-date "2013-10-26"; }
+
+    import opendaylight-flow-statistics { prefix flowstat; revision-date "2013-08-19"; }
+    import opendaylight-port-statistics { prefix portstat; revision-date "2013-12-14"; }
+    import opendaylight-queue-statistics { prefix queuestat; revision-date "2013-12-16"; }
+
+    description "Openflow direct statistics polling.";
+
+    revision "2016-05-11" {
+        description "Initial revision of direct statistics service";
+    }
+
+    grouping store-stats-grouping {
+        description "Store collected statistics to DS/operational";
+
+        leaf store-stats {
+            type boolean;
+            default false;
+        }
+    }
+
+    grouping stats-input-common-grouping {
+        description "Shared input parameters for all rpc statistics (routing context and datastore flag)";
+
+        uses inv:node-context-ref;
+        uses store-stats-grouping;
+    }
+
+    rpc get-flow-statistics {
+        description "Get statistics for given flow";
+
+        input {
+            uses stats-input-common-grouping;
+            uses flow-types:flow;
+        }
+
+        output {
+            uses flowstat:flow-and-statistics-map-list;
+        }
+    }
+
+    rpc get-group-statistics {
+        description "Get statistics for given group";
+
+        input {
+            uses stats-input-common-grouping;
+
+            leaf group-id {
+                type group-types:group-id;
+            }
+        }
+
+        output {
+            uses group-types:group-statistics-reply;
+        }
+    }
+
+    rpc get-meter-statistics {
+        description "Get statistics for given meter";
+
+        input {
+            uses stats-input-common-grouping;
+
+            leaf meter-id {
+                type meter-types:meter-id;
+            }
+        }
+
+        output {
+            uses meter-types:meter-statistics-reply;
+        }
+    }
+
+    rpc get-node-connector-statistics {
+        description "Get statistics for given node connector from the node";
+
+        input {
+            uses stats-input-common-grouping;
+
+            leaf node-connector-id {
+                description "Optional, if omitted, returns statistics for all ports";
+                type inv:node-connector-id;
+            }
+        }
+
+        output {
+            uses portstat:node-connector-statistics-and-port-number-map;
+        }
+    }
+
+    rpc get-queue-statistics {
+        description "Get statistics for given queues from given port of the node";
+
+        input {
+            uses stats-input-common-grouping;
+
+            leaf node-connector-id {
+                type inv:node-connector-id;
+            }
+
+            leaf queue-id {
+                type queue-types:queue-id;
+            }
+        }
+
+        output {
+            uses queuestat:queue-id-and-statistics-map;
+        }
+    }
+}
index 35125b54214b35279ede89e928717b82adc9fb9c..b2c70f70535cd40d58c6e22fb07a6199f927c3af 100644 (file)
@@ -138,6 +138,7 @@ public interface DeviceContext extends AutoCloseable,
      * @return sync. future for Slave and MD-SAL completition for Master
      */
     ListenableFuture<Void> shuttingDownDataStoreTransactions();
+
     /**
      * Method provides current devices connection context.
      *
index 6a982b1e6814174984140fe211beef174ff78adc..e8a8ccb90449b48aa753e4654db84dc91823cdc2 100644 (file)
@@ -24,6 +24,13 @@ public interface TxFacade {
     <T extends DataObject> void writeToTransaction(final LogicalDatastoreType store, final InstanceIdentifier<T> path,
                                                    final T data) throws Exception;
 
+    /**
+     * Method creates put operation using provided data in underlying transaction chain and flag to create missing parents
+     * WARNING: This method is slow because of additional reading cost. Use it only if you really need to create parents.
+     */
+    <T extends DataObject> void writeToTransactionWithParentsSlow(final LogicalDatastoreType store, final InstanceIdentifier<T> path,
+                                                                  final T data) throws Exception;
+
     /**
      * Method creates delete operation for provided path in underlying transaction chain.
      */
index d8e924a953230b09037610f6b4ca2714e8381111..1d82ea0f2f89d7e7784f5e12fc33088842ca7718 100644 (file)
@@ -333,7 +333,12 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi
     @Override
     public <T extends DataObject> void writeToTransaction(final LogicalDatastoreType store,
                                                           final InstanceIdentifier<T> path, final T data) throws Exception {
-        transactionChainManager.writeToTransaction(store, path, data);
+        transactionChainManager.writeToTransaction(store, path, data, false);
+    }
+
+    @Override
+    public <T extends DataObject> void writeToTransactionWithParentsSlow(LogicalDatastoreType store, InstanceIdentifier<T> path, T data) throws Exception {
+        transactionChainManager.writeToTransaction(store, path, data, true);
     }
 
     @Override
index 34b766f880278681534fdd97c56569bfc5897c8b..d85dab8f59632457938b55b0344792df1767e0c4 100644 (file)
@@ -215,11 +215,13 @@ class TransactionChainManager implements TransactionChainListener, AutoCloseable
     }
 
     <T extends DataObject> void writeToTransaction(final LogicalDatastoreType store,
-                                                   final InstanceIdentifier<T> path, final T data) throws Exception {
+                                                   final InstanceIdentifier<T> path,
+                                                   final T data,
+                                                   final boolean createParents) throws Exception {
         final WriteTransaction writeTx = getTransactionSafely();
         if (writeTx != null) {
             LOG.trace("writeToTransaction called with path {} ", path);
-            writeTx.put(store, path, data);
+            writeTx.put(store, path, data, createParents);
         } else {
             LOG.debug("WriteTx is null for node {}. Write data for {} was not realized.", nodeII, path);
             throw new Exception("Cannot write into transaction.");
index 1d812694de4ccb8ebe3cedc62fd80764d75e7ef8..f063b2ef51d69511fc26f61ba722e84eabb3e2a6 100644 (file)
@@ -40,7 +40,12 @@ public final class FlowsInTableService extends AbstractCompatibleStatService<Get
     protected OfHeader buildRequest(final Xid xid, final GetFlowStatisticsFromFlowTableInput input) {
         final MultipartRequestFlowCaseBuilder multipartRequestFlowCaseBuilder = new MultipartRequestFlowCaseBuilder();
         final MultipartRequestFlowBuilder mprFlowRequestBuilder = new MultipartRequestFlowBuilder();
-        mprFlowRequestBuilder.setTableId(input.getTableId());
+
+        if (input.getTableId() != null) {
+            mprFlowRequestBuilder.setTableId(input.getTableId());
+        } else {
+            mprFlowRequestBuilder.setTableId(OFConstants.OFPTT_ALL);
+        }
 
         if (input.getOutPort() != null) {
             mprFlowRequestBuilder.setOutPort(input.getOutPort().longValue());
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/AbstractDirectStatisticsService.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/AbstractDirectStatisticsService.java
new file mode 100644 (file)
index 0000000..efc9eb3
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.api.openflow.device.Xid;
+import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
+import org.opendaylight.openflowplugin.impl.services.AbstractMultipartService;
+import org.opendaylight.openflowplugin.impl.services.RequestInputUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.StoreStatsGrouping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.MultipartRequestBody;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.concurrent.Future;
+
+/**
+ * The abstract direct statistics service.
+ * This abstract service provides wrappers and tools for all other derived statistics services.
+ *
+ * @param <I> the input type parameter
+ * @param <O> the output type parameter
+ */
+public abstract class AbstractDirectStatisticsService<I extends StoreStatsGrouping, O> extends AbstractMultipartService<I> {
+
+    private final Function<RpcResult<List<MultipartReply>>, RpcResult<O>> resultTransformFunction =
+            new Function<RpcResult<List<MultipartReply>>, RpcResult<O>>() {
+                @Nullable
+                @Override
+                public RpcResult<O> apply(@Nullable RpcResult<List<MultipartReply>> input) {
+                    Preconditions.checkNotNull(input);
+                    final O reply = buildReply(input.getResult(), input.isSuccessful());
+                    return RpcResultBuilder.success(reply).build();
+                }
+            };
+
+    private final AsyncFunction<RpcResult<O>, RpcResult<O>> resultStoreFunction =
+            new AsyncFunction<RpcResult<O>, RpcResult<O>>() {
+                @Nullable
+                @Override
+                public ListenableFuture<RpcResult<O>> apply(@Nullable RpcResult<O> input) throws Exception {
+                    Preconditions.checkNotNull(input);
+
+                    if (input.isSuccessful()) {
+                        storeStatistics(input.getResult());
+                        getDeviceContext().submitTransaction(); // TODO: If submitTransaction will ever return future, chain it
+                    }
+
+                    return Futures.immediateFuture(input);
+                }
+            };
+
+    private final MultipartType multipartType;
+    private final OpenflowVersion ofVersion = OpenflowVersion.get(getVersion());
+
+    /**
+     * Instantiates a new Abstract direct statistics service.
+     *
+     * @param multipartType       the multipart type
+     * @param requestContextStack the request context stack
+     * @param deviceContext       the device context
+     */
+    protected AbstractDirectStatisticsService(MultipartType multipartType, RequestContextStack requestContextStack, DeviceContext deviceContext) {
+        super(requestContextStack, deviceContext);
+        this.multipartType = multipartType;
+    }
+
+    /**
+     * Handle input and reply future.
+     *
+     * @param input the input
+     * @return the future
+     */
+    public Future<RpcResult<O>> handleAndReply(final I input) {
+        final ListenableFuture<RpcResult<List<MultipartReply>>> rpcReply = handleServiceCall(input);
+        ListenableFuture<RpcResult<O>> rpcResult = Futures.transform(rpcReply, resultTransformFunction);
+
+        if (input.isStoreStats()) {
+            rpcResult = Futures.transform(rpcResult, resultStoreFunction);
+        }
+
+        return rpcResult;
+    }
+
+    @Override
+    protected OfHeader buildRequest(Xid xid, I input) throws Exception {
+        return RequestInputUtils.createMultipartHeader(multipartType, xid.getValue(), getVersion())
+                .setMultipartRequestBody(buildRequestBody(input))
+                .build();
+    }
+
+    /**
+     * Gets openflow version.
+     *
+     * @return the openflow version
+     */
+    protected OpenflowVersion getOfVersion() {
+        return ofVersion;
+    }
+
+    /**
+     * Build multipart request body.
+     *
+     * @param input the input
+     * @return the multipart request body
+     */
+    protected abstract MultipartRequestBody buildRequestBody(I input);
+
+    /**
+     * Build output from multipart reply input.
+     *
+     * @param input the input
+     * @return the output
+     */
+    protected abstract O buildReply(List<MultipartReply> input, boolean success);
+
+    /**
+     * Store statistics.
+     * TODO: Remove dependency on deviceContext from derived methods
+     * TODO: Return future, so we will be able to chain it
+     *
+     * @param output the output
+     * @throws Exception the exception
+     */
+    protected abstract void storeStatistics(O output) throws Exception;
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/FlowDirectStatisticsService.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/FlowDirectStatisticsService.java
new file mode 100644 (file)
index 0000000..72066b0
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowRegistryKey;
+import org.opendaylight.openflowplugin.impl.registry.flow.FlowRegistryKeyFactory;
+import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.FlowStatsResponseConvertor;
+import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.MatchReactor;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetFlowStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetFlowStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetFlowStatisticsOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.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.and.statistics.map.list.FlowAndStatisticsMapListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyFlowCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.flow._case.MultipartReplyFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.MultipartRequestBody;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestFlowCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.flow._case.MultipartRequestFlowBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The Flow direct statistics service.
+ */
+public class FlowDirectStatisticsService extends AbstractDirectStatisticsService<GetFlowStatisticsInput, GetFlowStatisticsOutput> {
+    private final FlowStatsResponseConvertor flowStatsConvertor = new FlowStatsResponseConvertor();
+
+    /**
+     * Instantiates a new Flow direct statistics service.
+     *
+     * @param requestContextStack the request context stack
+     * @param deviceContext       the device context
+     */
+    public FlowDirectStatisticsService(RequestContextStack requestContextStack, DeviceContext deviceContext) {
+        super(MultipartType.OFPMPFLOW, requestContextStack, deviceContext);
+    }
+
+    @Override
+    protected MultipartRequestBody buildRequestBody(GetFlowStatisticsInput input) {
+        final MultipartRequestFlowBuilder mprFlowRequestBuilder = new MultipartRequestFlowBuilder();
+
+        if (input.getTableId() != null) {
+            mprFlowRequestBuilder.setTableId(input.getTableId());
+        } else {
+            mprFlowRequestBuilder.setTableId(OFConstants.OFPTT_ALL);
+        }
+
+        if (input.getOutPort() != null) {
+            mprFlowRequestBuilder.setOutPort(input.getOutPort().longValue());
+        } else {
+            mprFlowRequestBuilder.setOutPort(OFConstants.OFPP_ANY);
+        }
+
+        if (input.getOutGroup() != null) {
+            mprFlowRequestBuilder.setOutGroup(input.getOutGroup());
+        } else {
+            mprFlowRequestBuilder.setOutGroup(OFConstants.OFPG_ANY);
+        }
+
+        if (input.getCookie() != null) {
+            mprFlowRequestBuilder.setCookie(input.getCookie().getValue());
+        } else {
+            mprFlowRequestBuilder.setCookie(OFConstants.DEFAULT_COOKIE);
+        }
+
+        if (input.getCookieMask() != null) {
+            mprFlowRequestBuilder.setCookieMask(input.getCookieMask().getValue());
+        } else {
+            mprFlowRequestBuilder.setCookieMask(OFConstants.DEFAULT_COOKIE_MASK);
+        }
+
+        MatchReactor.getInstance().convert(input.getMatch(), getVersion(), mprFlowRequestBuilder, getDatapathId());
+
+        return new MultipartRequestFlowCaseBuilder()
+                .setMultipartRequestFlow(mprFlowRequestBuilder.build())
+                .build();
+    }
+
+    @Override
+    protected GetFlowStatisticsOutput buildReply(List<MultipartReply> input, boolean success) {
+        final List<FlowAndStatisticsMapList> statsList = new ArrayList<>();
+
+        if (success) {
+            for (final MultipartReply mpReply : input) {
+                final MultipartReplyFlowCase caseBody = (MultipartReplyFlowCase) mpReply.getMultipartReplyBody();
+                final MultipartReplyFlow replyBody = caseBody.getMultipartReplyFlow();
+
+                final List<FlowAndStatisticsMapList> statsListPart = flowStatsConvertor.toSALFlowStatsList(replyBody.getFlowStats(), getDatapathId(), getOfVersion());
+
+                for (final FlowAndStatisticsMapList part : statsListPart) {
+                    final org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowId flowId =
+                            new org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowId(generateFlowId(part).getValue());
+
+                    statsList.add(new FlowAndStatisticsMapListBuilder(part)
+                            .setKey(new FlowAndStatisticsMapListKey(flowId))
+                            .setFlowId(flowId)
+                            .build());
+                }
+            }
+        }
+
+        return new GetFlowStatisticsOutputBuilder()
+                .setFlowAndStatisticsMapList(statsList)
+                .build();
+    }
+
+    @Override
+    protected void storeStatistics(GetFlowStatisticsOutput output) throws Exception {
+        final InstanceIdentifier<FlowCapableNode> nodePath = getDeviceContext()
+                .getDeviceState().getNodeInstanceIdentifier().augmentation(FlowCapableNode.class);
+
+        for (final FlowAndStatisticsMapList flowStatistics : output.getFlowAndStatisticsMapList()) {
+            final FlowId flowId = generateFlowId(flowStatistics);
+            final FlowKey flowKey = new FlowKey(flowId);
+
+            final FlowStatisticsDataBuilder flowStatisticsDataBld = new FlowStatisticsDataBuilder()
+                    .setFlowStatistics(new FlowStatisticsBuilder(flowStatistics).build());
+
+            final FlowBuilder flowBuilder = new FlowBuilder(flowStatistics)
+                    .addAugmentation(FlowStatisticsData.class, flowStatisticsDataBld.build())
+                    .setKey(flowKey);
+
+            final InstanceIdentifier<Flow> flowStatisticsPath = nodePath
+                    .child(Table.class, new TableKey(flowStatistics.getTableId()))
+                    .child(Flow.class, flowKey);
+
+            getDeviceContext().writeToTransactionWithParentsSlow(LogicalDatastoreType.OPERATIONAL, flowStatisticsPath, flowBuilder.build());
+        }
+    }
+
+    private FlowId generateFlowId(FlowAndStatisticsMapList flowStatistics) {
+        final FlowStatisticsDataBuilder flowStatisticsDataBld = new FlowStatisticsDataBuilder()
+                .setFlowStatistics(new FlowStatisticsBuilder(flowStatistics).build());
+
+        final FlowBuilder flowBuilder = new FlowBuilder(flowStatistics)
+                .addAugmentation(FlowStatisticsData.class, flowStatisticsDataBld.build());
+
+        final short tableId = flowStatistics.getTableId();
+        final FlowRegistryKey flowRegistryKey = FlowRegistryKeyFactory.create(flowBuilder.build());
+        return getDeviceContext().getDeviceFlowRegistry().storeIfNecessary(flowRegistryKey, tableId);
+    }
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/GroupDirectStatisticsService.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/GroupDirectStatisticsService.java
new file mode 100644 (file)
index 0000000..b7c650a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.GroupStatsResponseConvertor;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetGroupStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetGroupStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetGroupStatisticsOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyGroupCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.group._case.MultipartReplyGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.MultipartRequestBody;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestGroupCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.group._case.MultipartRequestGroupBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The Group direct statistics service.
+ */
+public class GroupDirectStatisticsService extends AbstractDirectStatisticsService<GetGroupStatisticsInput, GetGroupStatisticsOutput> {
+    private final GroupStatsResponseConvertor groupStatsConvertor = new GroupStatsResponseConvertor();
+
+    /**
+     * Instantiates a new Group direct statistics service.
+     *
+     * @param requestContextStack the request context stack
+     * @param deviceContext       the device context
+     */
+    public GroupDirectStatisticsService(RequestContextStack requestContextStack, DeviceContext deviceContext) {
+        super(MultipartType.OFPMPGROUP, requestContextStack, deviceContext);
+    }
+
+    @Override
+    protected MultipartRequestBody buildRequestBody(GetGroupStatisticsInput input) {
+        final MultipartRequestGroupBuilder mprGroupBuild = new MultipartRequestGroupBuilder();
+
+        if (input.getGroupId() != null) {
+            mprGroupBuild.setGroupId(new GroupId(input.getGroupId().getValue()));
+        } else {
+            mprGroupBuild.setGroupId(new GroupId(OFConstants.OFPG_ALL));
+        }
+
+        return new MultipartRequestGroupCaseBuilder()
+                .setMultipartRequestGroup(mprGroupBuild.build())
+                .build();
+    }
+
+    @Override
+    protected GetGroupStatisticsOutput buildReply(List<MultipartReply> input, boolean success) {
+        final List<GroupStats> groupStats = new ArrayList<>();
+
+        if (success) {
+            for (final MultipartReply mpReply : input) {
+                final MultipartReplyGroupCase caseBody = (MultipartReplyGroupCase) mpReply.getMultipartReplyBody();
+                final MultipartReplyGroup replyBody = caseBody.getMultipartReplyGroup();
+                groupStats.addAll(groupStatsConvertor.toSALGroupStatsList(replyBody.getGroupStats()));
+            }
+        }
+
+        return new GetGroupStatisticsOutputBuilder()
+                .setGroupStats(groupStats)
+                .build();
+    }
+
+    @Override
+    protected void storeStatistics(GetGroupStatisticsOutput output) throws Exception {
+        final InstanceIdentifier<FlowCapableNode> nodePath = getDeviceContext()
+                .getDeviceState().getNodeInstanceIdentifier().augmentation(FlowCapableNode.class);
+
+        for (final GroupStats groupStatistics : output.getGroupStats()) {
+            final InstanceIdentifier<GroupStatistics> groupStatisticsPath = nodePath
+                    .child(Group.class, new GroupKey(groupStatistics.getGroupId()))
+                    .augmentation(NodeGroupStatistics.class)
+                    .child(GroupStatistics.class);
+
+            final GroupStatistics stats = new GroupStatisticsBuilder(groupStatistics).build();
+            getDeviceContext().writeToTransactionWithParentsSlow(LogicalDatastoreType.OPERATIONAL, groupStatisticsPath, stats);
+        }
+    }
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/MeterDirectStatisticsService.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/MeterDirectStatisticsService.java
new file mode 100644 (file)
index 0000000..da6475e
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.MeterStatsResponseConvertor;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetMeterStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetMeterStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetMeterStatisticsOutputBuilder;
+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.MeterKey;
+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.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.statistics.reply.MeterStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MeterId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyMeterCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.meter._case.MultipartReplyMeter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.MultipartRequestBody;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestMeterCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.meter._case.MultipartRequestMeterBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The Meter direct statistics service.
+ */
+public class MeterDirectStatisticsService extends AbstractDirectStatisticsService<GetMeterStatisticsInput, GetMeterStatisticsOutput> {
+    private final MeterStatsResponseConvertor meterStatsConvertor = new MeterStatsResponseConvertor();
+
+    /**
+     * Instantiates a new Meter direct statistics service.
+     *
+     * @param requestContextStack the request context stack
+     * @param deviceContext       the device context
+     */
+    public MeterDirectStatisticsService(RequestContextStack requestContextStack, DeviceContext deviceContext) {
+        super(MultipartType.OFPMPMETER, requestContextStack, deviceContext);
+    }
+
+    @Override
+    protected MultipartRequestBody buildRequestBody(GetMeterStatisticsInput input) {
+        final MultipartRequestMeterBuilder mprMeterBuild = new MultipartRequestMeterBuilder();
+
+        if (input.getMeterId() != null) {
+            mprMeterBuild.setMeterId(new MeterId(input.getMeterId().getValue()));
+        } else {
+            mprMeterBuild.setMeterId(new MeterId(OFConstants.OFPM_ALL));
+        }
+
+        return new MultipartRequestMeterCaseBuilder()
+                .setMultipartRequestMeter(mprMeterBuild.build())
+                .build();
+    }
+
+    @Override
+    protected GetMeterStatisticsOutput buildReply(List<MultipartReply> input, boolean success) {
+        final List<MeterStats> meterStats = new ArrayList<>();
+
+        if (success) {
+            for (final MultipartReply mpReply : input) {
+                final MultipartReplyMeterCase caseBody = (MultipartReplyMeterCase) mpReply.getMultipartReplyBody();
+                final MultipartReplyMeter replyBody = caseBody.getMultipartReplyMeter();
+                meterStats.addAll(meterStatsConvertor.toSALMeterStatsList(replyBody.getMeterStats()));
+            }
+        }
+
+        return new GetMeterStatisticsOutputBuilder()
+                .setMeterStats(meterStats)
+                .build();
+    }
+
+    @Override
+    protected void storeStatistics(GetMeterStatisticsOutput output) throws Exception {
+        final InstanceIdentifier<FlowCapableNode> nodePath = getDeviceContext()
+                .getDeviceState().getNodeInstanceIdentifier().augmentation(FlowCapableNode.class);
+
+        for (final MeterStats meterStatistics : output.getMeterStats()) {
+            final InstanceIdentifier<MeterStatistics> meterPath = nodePath
+                    .child(Meter.class, new MeterKey(meterStatistics.getMeterId()))
+                    .augmentation(NodeMeterStatistics.class)
+                    .child(MeterStatistics.class);
+
+            final MeterStatistics stats = new MeterStatisticsBuilder(meterStatistics).build();
+            getDeviceContext().writeToTransactionWithParentsSlow(LogicalDatastoreType.OPERATIONAL, meterPath, stats);
+        }
+    }
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/NodeConnectorDirectStatisticsService.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/NodeConnectorDirectStatisticsService.java
new file mode 100644 (file)
index 0000000..6f6f496
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter32;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetNodeConnectorStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetNodeConnectorStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetNodeConnectorStatisticsOutputBuilder;
+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.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.duration.DurationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.BytesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.PacketsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyPortStatsCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.port.stats._case.MultipartReplyPortStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.port.stats._case.multipart.reply.port.stats.PortStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.MultipartRequestBody;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestPortStatsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.port.stats._case.MultipartRequestPortStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatistics;
+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.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMapKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The Node connector direct statistics service.
+ */
+public class NodeConnectorDirectStatisticsService extends AbstractDirectStatisticsService<GetNodeConnectorStatisticsInput, GetNodeConnectorStatisticsOutput> {
+    /**
+     * Instantiates a new Node connector direct statistics service.
+     *
+     * @param requestContextStack the request context stack
+     * @param deviceContext       the device context
+     */
+    public NodeConnectorDirectStatisticsService(RequestContextStack requestContextStack, DeviceContext deviceContext) {
+        super(MultipartType.OFPMPPORTSTATS, requestContextStack, deviceContext);
+    }
+
+    @Override
+    protected MultipartRequestBody buildRequestBody(GetNodeConnectorStatisticsInput input) {
+        final MultipartRequestPortStatsBuilder mprPortStatsBuilder = new MultipartRequestPortStatsBuilder();
+
+        if (input.getNodeConnectorId() != null) {
+            mprPortStatsBuilder.setPortNo(InventoryDataServiceUtil.portNumberfromNodeConnectorId(getOfVersion(), input.getNodeConnectorId()));
+        } else {
+            mprPortStatsBuilder.setPortNo(OFConstants.OFPP_ANY);
+        }
+
+        return new MultipartRequestPortStatsCaseBuilder()
+                .setMultipartRequestPortStats(mprPortStatsBuilder.build())
+                .build();
+    }
+
+    @Override
+    protected GetNodeConnectorStatisticsOutput buildReply(List<MultipartReply> input, boolean success) {
+        final List<NodeConnectorStatisticsAndPortNumberMap> nodeConnectorStatisticsAndPortNumberMap = new ArrayList<>();
+
+        if (success) {
+            for (final MultipartReply mpReply : input) {
+                final MultipartReplyPortStatsCase caseBody = (MultipartReplyPortStatsCase) mpReply.getMultipartReplyBody();
+                final MultipartReplyPortStats replyBody = caseBody.getMultipartReplyPortStats();
+
+                for (final PortStats portStats : replyBody.getPortStats()) {
+                    final NodeConnectorId nodeConnectorId = InventoryDataServiceUtil.nodeConnectorIdfromDatapathPortNo(
+                            getDatapathId(), portStats.getPortNo(), getOfVersion());
+
+                    final BytesBuilder bytesBuilder = new BytesBuilder()
+                            .setReceived(portStats.getRxBytes())
+                            .setTransmitted(portStats.getTxBytes());
+
+                    final PacketsBuilder packetsBuilder = new PacketsBuilder()
+                            .setReceived(portStats.getRxPackets())
+                            .setTransmitted(portStats.getTxPackets());
+
+                    final DurationBuilder durationBuilder = new DurationBuilder();
+
+                    if (portStats.getDurationSec() != null) {
+                        durationBuilder.setSecond(new Counter32(portStats.getDurationSec()));
+                    }
+
+                    if (portStats.getDurationNsec() != null) {
+                        durationBuilder.setNanosecond(new Counter32(portStats.getDurationNsec()));
+                    }
+
+                    final NodeConnectorStatisticsAndPortNumberMap stats = new NodeConnectorStatisticsAndPortNumberMapBuilder()
+                            .setBytes(bytesBuilder.build())
+                            .setPackets(packetsBuilder.build())
+                            .setNodeConnectorId(nodeConnectorId)
+                            .setDuration(durationBuilder.build())
+                            .setCollisionCount(portStats.getCollisions())
+                            .setKey(new NodeConnectorStatisticsAndPortNumberMapKey(nodeConnectorId))
+                            .setReceiveCrcError(portStats.getRxCrcErr()).setReceiveDrops(portStats.getRxDropped())
+                            .setReceiveErrors(portStats.getRxErrors())
+                            .setReceiveFrameError(portStats.getRxFrameErr())
+                            .setReceiveOverRunError(portStats.getRxOverErr())
+                            .setTransmitDrops(portStats.getTxDropped())
+                            .setTransmitErrors(portStats.getTxErrors())
+                            .build();
+
+                    nodeConnectorStatisticsAndPortNumberMap.add(stats);
+                }
+            }
+        }
+
+        return new GetNodeConnectorStatisticsOutputBuilder()
+                .setNodeConnectorStatisticsAndPortNumberMap(nodeConnectorStatisticsAndPortNumberMap)
+                .build();
+    }
+
+    @Override
+    protected void storeStatistics(GetNodeConnectorStatisticsOutput output) throws Exception {
+        final InstanceIdentifier<Node> nodePath = getDeviceContext().getDeviceState().getNodeInstanceIdentifier();
+
+        for (final NodeConnectorStatisticsAndPortNumberMap nodeConnectorStatistics : output.getNodeConnectorStatisticsAndPortNumberMap()) {
+            final InstanceIdentifier<FlowCapableNodeConnectorStatistics> nodeConnectorPath = nodePath
+                    .child(NodeConnector.class, new NodeConnectorKey(nodeConnectorStatistics.getNodeConnectorId()))
+                    .augmentation(FlowCapableNodeConnectorStatisticsData.class)
+                    .child(FlowCapableNodeConnectorStatistics.class);
+
+            final FlowCapableNodeConnectorStatistics stats = new FlowCapableNodeConnectorStatisticsBuilder(nodeConnectorStatistics).build();
+            getDeviceContext().writeToTransactionWithParentsSlow(LogicalDatastoreType.OPERATIONAL, nodeConnectorPath, stats);
+        }
+    }
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/OpendaylightDirectStatisticsServiceImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/OpendaylightDirectStatisticsServiceImpl.java
new file mode 100644 (file)
index 0000000..b96ae21
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetFlowStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetFlowStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetGroupStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetGroupStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetMeterStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetMeterStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetNodeConnectorStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetNodeConnectorStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetQueueStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetQueueStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.OpendaylightDirectStatisticsService;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+import java.util.Optional;
+import java.util.concurrent.Future;
+
+/**
+ * The Opendaylight direct statistics service.
+ * This service handles RPC requests, sends them to registered handlers and returns their replies.
+ */
+public class OpendaylightDirectStatisticsServiceImpl implements OpendaylightDirectStatisticsService {
+    private final OpendaylightDirectStatisticsServiceProvider provider;
+
+    /**
+     * Instantiates a new Opendaylight direct statistics service.
+     *
+     * @param provider the openflow direct statistics service provider
+     */
+    public OpendaylightDirectStatisticsServiceImpl(final OpendaylightDirectStatisticsServiceProvider provider) {
+        this.provider = provider;
+    }
+
+    @Override
+    public Future<RpcResult<GetGroupStatisticsOutput>> getGroupStatistics(GetGroupStatisticsInput input) {
+        final Optional<GroupDirectStatisticsService> service = provider.lookup(GroupDirectStatisticsService.class);
+
+        if (!service.isPresent()) {
+            return missingImplementation(GroupDirectStatisticsService.class);
+        }
+
+        return service.get().handleAndReply(input);
+    }
+
+    @Override
+    public Future<RpcResult<GetQueueStatisticsOutput>> getQueueStatistics(GetQueueStatisticsInput input) {
+        final Optional<QueueDirectStatisticsService> service = provider.lookup(QueueDirectStatisticsService.class);
+
+        if (!service.isPresent()) {
+            return missingImplementation(QueueDirectStatisticsService.class);
+        }
+
+        return service.get().handleAndReply(input);
+    }
+
+    @Override
+    public Future<RpcResult<GetFlowStatisticsOutput>> getFlowStatistics(GetFlowStatisticsInput input) {
+        final Optional<FlowDirectStatisticsService> service = provider.lookup(FlowDirectStatisticsService.class);
+
+        if (!service.isPresent()) {
+            return missingImplementation(FlowDirectStatisticsService.class);
+        }
+
+        return service.get().handleAndReply(input);
+    }
+
+    @Override
+    public Future<RpcResult<GetMeterStatisticsOutput>> getMeterStatistics(GetMeterStatisticsInput input) {
+        final Optional<MeterDirectStatisticsService> service = provider.lookup(MeterDirectStatisticsService.class);
+
+        if (!service.isPresent()) {
+            return missingImplementation(MeterDirectStatisticsService.class);
+        }
+
+        return service.get().handleAndReply(input);
+    }
+
+    @Override
+    public Future<RpcResult<GetNodeConnectorStatisticsOutput>> getNodeConnectorStatistics(GetNodeConnectorStatisticsInput input) {
+        final Optional<NodeConnectorDirectStatisticsService> service = provider.lookup(NodeConnectorDirectStatisticsService.class);
+
+        if (!service.isPresent()) {
+            return missingImplementation(NodeConnectorDirectStatisticsService.class);
+        }
+
+        return service.get().handleAndReply(input);
+    }
+
+    private <T extends DataObject> Future<RpcResult<T>> missingImplementation(Class service) {
+        return RpcResultBuilder.<T>failed().withError(
+                RpcError.ErrorType.APPLICATION,
+                String.format("No implementation found for direct statistics service %s.", service.getCanonicalName()))
+                .buildFuture();
+    }
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/OpendaylightDirectStatisticsServiceProvider.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/OpendaylightDirectStatisticsServiceProvider.java
new file mode 100644 (file)
index 0000000..daecefb
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * The Opendaylight direct statistics service provider.
+ */
+public class OpendaylightDirectStatisticsServiceProvider {
+    private Map<Class<? extends AbstractDirectStatisticsService>, AbstractDirectStatisticsService> services = new HashMap<>();
+
+    /**
+     * Register direct statistics service.
+     *
+     * @param type    the service type
+     * @param service the service instance
+     */
+    public void register(Class<? extends AbstractDirectStatisticsService> type, AbstractDirectStatisticsService service) {
+        if (services.containsKey(type)) return;
+
+        services.put(type, service);
+    }
+
+    /**
+     * Lookup direct statistics service.
+     *
+     * @param <T>  the type parameter
+     * @param type the service type
+     * @return the service instance
+     */
+    public <T extends AbstractDirectStatisticsService> Optional<T> lookup(Class<T> type) {
+        if (!services.containsKey(type)) return Optional.empty();
+
+        return Optional.of(type.cast(services.get(type)));
+    }
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/QueueDirectStatisticsService.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/QueueDirectStatisticsService.java
new file mode 100644 (file)
index 0000000..88f97dc
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter32;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter64;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetQueueStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetQueueStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetQueueStatisticsOutputBuilder;
+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.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.model.statistics.types.rev130925.duration.DurationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyQueueCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.queue._case.MultipartReplyQueue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.queue._case.multipart.reply.queue.QueueStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.MultipartRequestBody;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestQueueCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.queue._case.MultipartRequestQueueBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.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.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMapBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The Queue direct statistics service.
+ */
+public class QueueDirectStatisticsService extends AbstractDirectStatisticsService<GetQueueStatisticsInput, GetQueueStatisticsOutput> {
+    /**
+     * Instantiates a new Queue direct statistics service.
+     *
+     * @param requestContextStack the request context stack
+     * @param deviceContext       the device context
+     */
+    public QueueDirectStatisticsService(RequestContextStack requestContextStack, DeviceContext deviceContext) {
+        super(MultipartType.OFPMPQUEUE, requestContextStack, deviceContext);
+    }
+
+    @Override
+    protected MultipartRequestBody buildRequestBody(GetQueueStatisticsInput input) {
+        final MultipartRequestQueueBuilder mprQueueBuilder = new MultipartRequestQueueBuilder();
+
+        if (input.getQueueId() != null) {
+            mprQueueBuilder.setQueueId(input.getQueueId().getValue());
+        } else {
+            mprQueueBuilder.setQueueId(OFConstants.OFPQ_ALL);
+        }
+
+        if (input.getNodeConnectorId() != null) {
+            mprQueueBuilder.setPortNo(InventoryDataServiceUtil.portNumberfromNodeConnectorId(getOfVersion(), input.getNodeConnectorId()));
+        } else {
+            mprQueueBuilder.setPortNo(OFConstants.OFPP_ANY);
+        }
+
+        return new MultipartRequestQueueCaseBuilder()
+                .setMultipartRequestQueue(mprQueueBuilder.build())
+                .build();
+    }
+
+    @Override
+    protected GetQueueStatisticsOutput buildReply(List<MultipartReply> input, boolean success) {
+        final List<QueueIdAndStatisticsMap> queueIdAndStatisticsMap = new ArrayList<>();
+
+        if (success) {
+            for (final MultipartReply mpReply : input) {
+                final MultipartReplyQueueCase caseBody = (MultipartReplyQueueCase) mpReply.getMultipartReplyBody();
+                final MultipartReplyQueue replyBody = caseBody.getMultipartReplyQueue();
+
+                for (final QueueStats queueStats : replyBody.getQueueStats()) {
+                    final DurationBuilder durationBuilder = new DurationBuilder()
+                            .setSecond(new Counter32(queueStats.getDurationSec()))
+                            .setNanosecond(new Counter32(queueStats.getDurationNsec()));
+
+                    final QueueIdAndStatisticsMapBuilder statsBuilder = new QueueIdAndStatisticsMapBuilder()
+                            .setNodeConnectorId(InventoryDataServiceUtil.nodeConnectorIdfromDatapathPortNo(
+                                    getDatapathId(), queueStats.getPortNo(), getOfVersion()))
+                            .setTransmissionErrors(new Counter64(queueStats.getTxErrors()))
+                            .setTransmittedBytes(new Counter64(queueStats.getTxBytes()))
+                            .setTransmittedPackets(new Counter64(queueStats.getTxPackets()))
+                            .setQueueId(new QueueId(queueStats.getQueueId()))
+                            .setDuration(durationBuilder.build());
+
+                    queueIdAndStatisticsMap.add(statsBuilder.build());
+                }
+            }
+        }
+
+        return new GetQueueStatisticsOutputBuilder()
+                .setQueueIdAndStatisticsMap(queueIdAndStatisticsMap)
+                .build();
+    }
+
+    @Override
+    protected void storeStatistics(GetQueueStatisticsOutput output) throws Exception {
+        final InstanceIdentifier<Node> nodePath = getDeviceContext().getDeviceState().getNodeInstanceIdentifier();
+
+        for (final QueueIdAndStatisticsMap queueStatistics : output.getQueueIdAndStatisticsMap()) {
+            if (queueStatistics.getQueueId() != null) {
+                final QueueKey qKey = new QueueKey(queueStatistics.getQueueId());
+
+                final FlowCapableNodeConnectorQueueStatistics statChild =
+                        new FlowCapableNodeConnectorQueueStatisticsBuilder(queueStatistics).build();
+
+                final FlowCapableNodeConnectorQueueStatisticsDataBuilder statBuild =
+                        new FlowCapableNodeConnectorQueueStatisticsDataBuilder()
+                                .setFlowCapableNodeConnectorQueueStatistics(statChild);
+
+                final InstanceIdentifier<Queue> queueStatisticsPath = nodePath
+                        .child(NodeConnector.class, new NodeConnectorKey(queueStatistics.getNodeConnectorId()))
+                        .augmentation(FlowCapableNodeConnector.class)
+                        .child(Queue.class, qKey);
+
+                final Queue stats = new QueueBuilder()
+                        .setKey(qKey)
+                        .setQueueId(queueStatistics.getQueueId())
+                        .addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, statBuild.build()).build();
+
+                getDeviceContext().writeToTransactionWithParentsSlow(LogicalDatastoreType.OPERATIONAL, queueStatisticsPath, stats);
+            }
+        }
+    }
+}
\ No newline at end of file
index 708410e69cc14cb198332e5d2da154f38a3ca261..05806e9b9a120077b26bfd59ab8a2572e43e2602 100644 (file)
@@ -37,6 +37,14 @@ import org.opendaylight.openflowplugin.impl.statistics.services.OpendaylightMete
 import org.opendaylight.openflowplugin.impl.statistics.services.OpendaylightPortStatisticsServiceImpl;
 import org.opendaylight.openflowplugin.impl.statistics.services.OpendaylightQueueStatisticsServiceImpl;
 import org.opendaylight.openflowplugin.impl.statistics.services.compatibility.OpendaylightFlowStatisticsServiceDelegateImpl;
+import org.opendaylight.openflowplugin.impl.statistics.services.direct.FlowDirectStatisticsService;
+import org.opendaylight.openflowplugin.impl.statistics.services.direct.GroupDirectStatisticsService;
+import org.opendaylight.openflowplugin.impl.statistics.services.direct.MeterDirectStatisticsService;
+import org.opendaylight.openflowplugin.impl.statistics.services.direct.NodeConnectorDirectStatisticsService;
+import org.opendaylight.openflowplugin.impl.statistics.services.direct.OpendaylightDirectStatisticsServiceImpl;
+import org.opendaylight.openflowplugin.impl.statistics.services.direct.OpendaylightDirectStatisticsServiceProvider;
+import org.opendaylight.openflowplugin.impl.statistics.services.direct.QueueDirectStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.OpendaylightDirectStatisticsService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.echo.service.rev150305.SalEchoService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.message.service.rev151020.SalExperimenterMessageService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.SalFlatBatchService;
@@ -102,6 +110,15 @@ public class MdSalRegistrationUtils {
         rpcContext.registerRpcServiceImplementation(NodeConfigService.class, new NodeConfigServiceImpl(rpcContext, deviceContext));
         rpcContext.registerRpcServiceImplementation(OpendaylightFlowStatisticsService.class, OpendaylightFlowStatisticsServiceImpl.createWithOook(rpcContext, deviceContext));
 
+        // Direct statistics gathering
+        final OpendaylightDirectStatisticsServiceProvider statisticsProvider = new OpendaylightDirectStatisticsServiceProvider();
+        statisticsProvider.register(FlowDirectStatisticsService.class, new FlowDirectStatisticsService(rpcContext, deviceContext));
+        statisticsProvider.register(GroupDirectStatisticsService.class, new GroupDirectStatisticsService(rpcContext, deviceContext));
+        statisticsProvider.register(MeterDirectStatisticsService.class, new MeterDirectStatisticsService(rpcContext, deviceContext));
+        statisticsProvider.register(NodeConnectorDirectStatisticsService.class, new NodeConnectorDirectStatisticsService(rpcContext, deviceContext));
+        statisticsProvider.register(QueueDirectStatisticsService.class, new QueueDirectStatisticsService(rpcContext, deviceContext));
+        rpcContext.registerRpcServiceImplementation(OpendaylightDirectStatisticsService.class, new OpendaylightDirectStatisticsServiceImpl(statisticsProvider));
+
         final SalFlatBatchServiceImpl salFlatBatchService = new SalFlatBatchServiceImpl(
                 new SalFlowsBatchServiceImpl(salFlowService, flowCapableTransactionService),
                 new SalGroupsBatchServiceImpl(salGroupService, flowCapableTransactionService),
@@ -152,6 +169,7 @@ public class MdSalRegistrationUtils {
         rpcContext.unregisterRpcServiceImplementation(SalFlatBatchService.class);
         // TODO: experimenter symmetric and multipart message services
         rpcContext.unregisterRpcServiceImplementation(SalExperimenterMessageService.class);
+        rpcContext.unregisterRpcServiceImplementation(OpendaylightDirectStatisticsService.class);
     }
 
     /**
index 2c7d0c263a8fd99cd06020915734e3c6dcfb7f67..cd3a89bc3836509af4441a2a8788753d7c51576b 100644 (file)
@@ -104,10 +104,10 @@ public class TransactionChainManagerTest {
     @Test
     public void testWriteToTransaction() throws Exception {
         final Node data = new NodeBuilder().setId(nodeId).build();
-        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data);
+        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data, false);
 
         Mockito.verify(txChain).newWriteOnlyTransaction();
-        Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data);
+        Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data, false);
     }
 
     /**
@@ -118,11 +118,11 @@ public class TransactionChainManagerTest {
     public void testSubmitTransaction() throws Exception {
         final Node data = new NodeBuilder().setId(nodeId).build();
         txChainManager.initialSubmitWriteTransaction();
-        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data);
+        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data, false);
         txChainManager.submitWriteTransaction();
 
         Mockito.verify(txChain).newWriteOnlyTransaction();
-        Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data);
+        Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data, false);
         Mockito.verify(writeTx).submit();
     }
 
@@ -133,11 +133,11 @@ public class TransactionChainManagerTest {
     @Test
     public void testSubmitTransaction1() throws Exception {
         final Node data = new NodeBuilder().setId(nodeId).build();
-        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data);
+        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data, false);
         txChainManager.submitWriteTransaction();
 
         Mockito.verify(txChain).newWriteOnlyTransaction();
-        Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data);
+        Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data, false);
         Mockito.verify(writeTx, Mockito.never()).submit();
     }
 
@@ -149,11 +149,11 @@ public class TransactionChainManagerTest {
         Mockito.when(writeTx.submit()).thenReturn(Futures.<Void, TransactionCommitFailedException>immediateFailedCheckedFuture(new TransactionCommitFailedException("mock")));
         final Node data = new NodeBuilder().setId(nodeId).build();
         txChainManager.initialSubmitWriteTransaction();
-        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data);
+        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data, false);
         txChainManager.submitWriteTransaction();
 
         Mockito.verify(txChain).newWriteOnlyTransaction();
-        Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data);
+        Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data, false);
         Mockito.verify(writeTx).submit();
     }
 
@@ -165,11 +165,11 @@ public class TransactionChainManagerTest {
     @Test
     public void testEnableCounter1() throws Exception {
         final Node data = new NodeBuilder().setId(nodeId).build();
-        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data);
-        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data);
+        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data, false);
+        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data, false);
 
         Mockito.verify(txChain).newWriteOnlyTransaction();
-        Mockito.verify(writeTx, Mockito.times(2)).put(LogicalDatastoreType.CONFIGURATION, path, data);
+        Mockito.verify(writeTx, Mockito.times(2)).put(LogicalDatastoreType.CONFIGURATION, path, data, false);
         Mockito.verify(writeTx, Mockito.never()).submit();
     }
 
@@ -212,12 +212,12 @@ public class TransactionChainManagerTest {
     public void testDeactivateTransactionChainManagerFailed() throws Exception {
         Mockito.when(writeTx.submit()).thenReturn(Futures.<Void, TransactionCommitFailedException>immediateFailedCheckedFuture(new TransactionCommitFailedException("mock")));
         final Node data = new NodeBuilder().setId(nodeId).build();
-        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data);
+        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data, false);
 
         txChainManager.deactivateTransactionManager();
 
         Mockito.verify(txChain).newWriteOnlyTransaction();
-        Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data);
+        Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data, false);
         Mockito.verify(writeTx).submit();
         Mockito.verify(txChain).close();
     }
@@ -225,12 +225,12 @@ public class TransactionChainManagerTest {
     @Test
     public void testShuttingDown() throws Exception{
         final Node data = new NodeBuilder().setId(nodeId).build();
-        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data);
+        txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data, false);
 
         txChainManager.shuttingDown();
 
         Mockito.verify(txChain).newWriteOnlyTransaction();
-        Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data);
+        Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data, false);
         Mockito.verify(writeTx).submit();
     }
 
diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/AbstractDirectStatisticsServiceTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/AbstractDirectStatisticsServiceTest.java
new file mode 100644 (file)
index 0000000..7263b98
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueue;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.api.openflow.device.TranslatorLibrary;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.MultiMsgCollector;
+import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
+import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy;
+import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
+import org.opendaylight.openflowplugin.openflow.md.util.OpenflowPortsUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+import java.math.BigInteger;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public abstract class AbstractDirectStatisticsServiceTest {
+    protected static final Long PORT_NO = 1L;
+    protected static final BigInteger DATAPATH_ID = BigInteger.TEN;
+    protected static final short OF_VERSION = OFConstants.OFP_VERSION_1_3;
+    protected static final String NODE_ID = "openflow:1";
+
+    @Mock
+    protected RequestContextStack requestContextStack;
+    @Mock
+    protected DeviceContext deviceContext;
+    @Mock
+    protected ConnectionContext connectionContext;
+    @Mock
+    protected FeaturesReply features;
+    @Mock
+    protected MessageSpy messageSpy;
+    @Mock
+    protected OutboundQueue outboundQueueProvider;
+    @Mock
+    protected MultiMsgCollector multiMsgCollector;
+    @Mock
+    protected TranslatorLibrary translatorLibrary;
+    @Mock
+    protected DeviceState deviceState;
+    @Mock
+    protected GetFeaturesOutput getFeaturesOutput;
+
+    protected NodeConnectorId nodeConnectorId;
+    protected KeyedInstanceIdentifier<Node, NodeKey> nodeInstanceIdentifier;
+
+    protected static NodeRef createNodeRef(String nodeIdValue) {
+        InstanceIdentifier<Node> nodePath = InstanceIdentifier.create(Nodes.class)
+                .child(Node.class, new NodeKey(new NodeId(nodeIdValue)));
+
+        return new NodeRef(nodePath);
+    }
+
+    @Before
+    public void init() throws Exception {
+        OpenflowPortsUtil.init();
+
+        nodeConnectorId = InventoryDataServiceUtil.nodeConnectorIdfromDatapathPortNo(
+                DATAPATH_ID, PORT_NO, OpenflowVersion.get(OF_VERSION));
+
+        nodeInstanceIdentifier = InstanceIdentifier
+                .create(Nodes.class)
+                .child(Node.class, new NodeKey(new NodeId(NODE_ID)));
+
+        when(deviceContext.getPrimaryConnectionContext()).thenReturn(connectionContext);
+        when(deviceContext.getMessageSpy()).thenReturn(messageSpy);
+        when(deviceContext.getMultiMsgCollector(any())).thenReturn(multiMsgCollector);
+        when(deviceContext.oook()).thenReturn(translatorLibrary);
+        when(deviceContext.getDeviceState()).thenReturn(deviceState);
+        when(deviceContext.getDeviceState()).thenReturn(deviceState);
+        when(deviceState.getNodeInstanceIdentifier()).thenReturn(nodeInstanceIdentifier);
+        when(deviceState.getNodeId()).thenReturn(new NodeId(NODE_ID));
+        when(deviceState.getVersion()).thenReturn(OF_VERSION);
+        when(deviceState.getFeatures()).thenReturn(getFeaturesOutput);
+        when(getFeaturesOutput.getVersion()).thenReturn(OF_VERSION);
+        when(getFeaturesOutput.getDatapathId()).thenReturn(DATAPATH_ID);
+        when(connectionContext.getFeatures()).thenReturn(features);
+        when(connectionContext.getOutboundQueueProvider()).thenReturn(outboundQueueProvider);
+        when(features.getVersion()).thenReturn(OF_VERSION);
+        when(features.getDatapathId()).thenReturn(DATAPATH_ID);
+        setUp();
+    }
+
+    protected abstract void setUp() throws Exception;
+
+    @Test
+    public abstract void testBuildRequestBody() throws Exception;
+
+    @Test
+    public abstract void testBuildReply() throws Exception;
+
+    @Test
+    public abstract void testStoreStatistics() throws Exception;
+}
\ No newline at end of file
diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/FlowDirectStatisticsServiceTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/FlowDirectStatisticsServiceTest.java
new file mode 100644 (file)
index 0000000..11b2b63
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.openflowplugin.api.openflow.registry.flow.DeviceFlowRegistry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetFlowStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetFlowStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowAndStatisticsMap;
+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.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.FlowModFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyFlowCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.flow._case.MultipartReplyFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.flow._case.multipart.reply.flow.FlowStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestFlowCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.flow._case.MultipartRequestFlow;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class FlowDirectStatisticsServiceTest extends AbstractDirectStatisticsServiceTest {
+    static final Short TABLE_NO = 1;
+    private FlowDirectStatisticsService service;
+
+    @Override
+    public void setUp() throws Exception {
+        service = new FlowDirectStatisticsService(requestContextStack, deviceContext);
+        final DeviceFlowRegistry registry = mock(DeviceFlowRegistry.class);
+        when(registry.storeIfNecessary(any(), eq(TABLE_NO))).thenReturn(new FlowId("1"));
+        when(deviceContext.getDeviceFlowRegistry()).thenReturn(registry);
+    }
+
+    @Override
+    public void testBuildRequestBody() throws Exception {
+        final GetFlowStatisticsInput input = mock(GetFlowStatisticsInput.class);
+
+        when(input.getNode()).thenReturn(createNodeRef(NODE_ID));
+        when(input.getTableId()).thenReturn(TABLE_NO);
+
+        final MultipartRequestFlowCase body = (MultipartRequestFlowCase) service.buildRequestBody(input);
+        final MultipartRequestFlow flow = body.getMultipartRequestFlow();
+
+        assertEquals(TABLE_NO, flow.getTableId());
+    }
+
+    @Override
+    public void testBuildReply() throws Exception {
+        final MultipartReply reply = mock(MultipartReply.class);
+        final MultipartReplyFlowCase flowCase = mock(MultipartReplyFlowCase.class);
+        final MultipartReplyFlow flow = mock(MultipartReplyFlow.class);
+        final FlowStats flowStat = mock(FlowStats.class);
+        final List<FlowStats> flowStats = Arrays.asList(flowStat);
+        final List<MultipartReply> input = Arrays.asList(reply);
+
+        when(flow.getFlowStats()).thenReturn(flowStats);
+        when(flowCase.getMultipartReplyFlow()).thenReturn(flow);
+        when(reply.getMultipartReplyBody()).thenReturn(flowCase);
+
+        when(flowStat.getTableId()).thenReturn(TABLE_NO);
+        when(flowStat.getByteCount()).thenReturn(BigInteger.ONE);
+        when(flowStat.getPacketCount()).thenReturn(BigInteger.ONE);
+        when(flowStat.getFlags()).thenReturn(mock(FlowModFlags.class));
+        when(flowStat.getMatch()).thenReturn(new org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.grouping.MatchBuilder()
+                .setMatchEntry(Collections.emptyList())
+                .build());
+
+        final GetFlowStatisticsOutput output = service.buildReply(input, true);
+        assertTrue(output.getFlowAndStatisticsMapList().size() > 0);
+
+        final FlowAndStatisticsMap stats = output.getFlowAndStatisticsMapList().get(0);
+
+        assertEquals(stats.getTableId(), TABLE_NO);
+    }
+
+    @Override
+    public void testStoreStatistics() throws Exception {
+        final FlowAndStatisticsMapList stat = mock(FlowAndStatisticsMapList.class);
+        when(stat.getTableId()).thenReturn(TABLE_NO);
+        when(stat.getMatch()).thenReturn(new MatchBuilder().build());
+
+        final List<FlowAndStatisticsMapList> stats = Arrays.asList(stat);
+        final GetFlowStatisticsOutput output = mock(GetFlowStatisticsOutput.class);
+        when(output.getFlowAndStatisticsMapList()).thenReturn(stats);
+
+        service.storeStatistics(output);
+        verify(deviceContext).writeToTransactionWithParentsSlow(eq(LogicalDatastoreType.OPERATIONAL), any(), any());
+    }
+}
\ No newline at end of file
diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/GroupDirectStatisticsServiceTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/GroupDirectStatisticsServiceTest.java
new file mode 100644 (file)
index 0000000..e948929
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetGroupStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetGroupStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyGroupCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.group._case.MultipartReplyGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.group._case.multipart.reply.group.GroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestGroupCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.group._case.MultipartRequestGroup;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class GroupDirectStatisticsServiceTest extends AbstractDirectStatisticsServiceTest {
+    static final Long GROUP_NO = 1L;
+    private GroupDirectStatisticsService service;
+
+    @Override
+    public void setUp() throws Exception {
+        service = new GroupDirectStatisticsService(requestContextStack, deviceContext);
+    }
+
+    @Override
+    public void testBuildRequestBody() throws Exception {
+        final GetGroupStatisticsInput input = mock(GetGroupStatisticsInput.class);
+
+        when(input.getNode()).thenReturn(createNodeRef(NODE_ID));
+        when(input.getGroupId()).thenReturn(new GroupId(GROUP_NO));
+
+        final MultipartRequestGroupCase body = (MultipartRequestGroupCase) service.buildRequestBody(input);
+        final MultipartRequestGroup group = body.getMultipartRequestGroup();
+
+        assertEquals(GROUP_NO, group.getGroupId().getValue());
+    }
+
+    @Override
+    public void testBuildReply() throws Exception {
+        final MultipartReply reply = mock(MultipartReply.class);
+        final MultipartReplyGroupCase groupCase = mock(MultipartReplyGroupCase.class);
+        final MultipartReplyGroup group = mock(MultipartReplyGroup.class);
+        final GroupStats groupStat = mock(GroupStats.class);
+        final List<GroupStats> groupStats = Arrays.asList(groupStat);
+        final List<MultipartReply> input = Arrays.asList(reply);
+
+        when(group.getGroupStats()).thenReturn(groupStats);
+        when(groupCase.getMultipartReplyGroup()).thenReturn(group);
+        when(reply.getMultipartReplyBody()).thenReturn(groupCase);
+
+        when(groupStat.getGroupId()).thenReturn(new org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.GroupId(GROUP_NO));
+        when(groupStat.getByteCount()).thenReturn(BigInteger.ONE);
+        when(groupStat.getPacketCount()).thenReturn(BigInteger.ONE);
+
+        final GetGroupStatisticsOutput output = service.buildReply(input, true);
+        assertTrue(output.getGroupStats().size() > 0);
+
+        final org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats stats =
+                output.getGroupStats().get(0);
+
+        assertEquals(stats.getGroupId().getValue(), GROUP_NO);
+    }
+
+    @Override
+    public void testStoreStatistics() throws Exception {
+        final org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats stat = mock(org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats.class);
+        when(stat.getGroupId()).thenReturn(new GroupId(GROUP_NO));
+
+        final List<org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats> stats = Arrays.asList(stat);
+        final GetGroupStatisticsOutput output = mock(GetGroupStatisticsOutput.class);
+        when(output.getGroupStats()).thenReturn(stats);
+
+        service.storeStatistics(output);
+        verify(deviceContext).writeToTransactionWithParentsSlow(eq(LogicalDatastoreType.OPERATIONAL), any(), any());
+    }
+}
\ No newline at end of file
diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/MeterDirectStatisticsServiceTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/MeterDirectStatisticsServiceTest.java
new file mode 100644 (file)
index 0000000..7c83703
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetMeterStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetMeterStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyMeterCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.meter._case.MultipartReplyMeter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.meter._case.multipart.reply.meter.MeterStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestMeterCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.meter._case.MultipartRequestMeter;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class MeterDirectStatisticsServiceTest extends AbstractDirectStatisticsServiceTest {
+    static final Long METER_NO = 1L;
+    private MeterDirectStatisticsService service;
+
+    @Override
+    public void setUp() throws Exception {
+        service = new MeterDirectStatisticsService(requestContextStack, deviceContext);
+    }
+
+    @Override
+    public void testBuildRequestBody() throws Exception {
+        final GetMeterStatisticsInput input = mock(GetMeterStatisticsInput.class);
+
+        when(input.getNode()).thenReturn(createNodeRef(NODE_ID));
+        when(input.getMeterId()).thenReturn(new MeterId(METER_NO));
+
+        final MultipartRequestMeterCase body = (MultipartRequestMeterCase) service.buildRequestBody(input);
+        final MultipartRequestMeter meter = body.getMultipartRequestMeter();
+
+        assertEquals(METER_NO, meter.getMeterId().getValue());
+    }
+
+    @Override
+    public void testBuildReply() throws Exception {
+        final MultipartReply reply = mock(MultipartReply.class);
+        final MultipartReplyMeterCase MeterCase = mock(MultipartReplyMeterCase.class);
+        final MultipartReplyMeter meter = mock(MultipartReplyMeter.class);
+        final MeterStats meterStat = mock(MeterStats.class);
+        final List<MeterStats> meterStats = Arrays.asList(meterStat);
+        final List<MultipartReply> input = Arrays.asList(reply);
+
+        when(meter.getMeterStats()).thenReturn(meterStats);
+        when(MeterCase.getMultipartReplyMeter()).thenReturn(meter);
+        when(reply.getMultipartReplyBody()).thenReturn(MeterCase);
+
+        when(meterStat.getMeterId()).thenReturn(new org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MeterId(METER_NO));
+        when(meterStat.getByteInCount()).thenReturn(BigInteger.ONE);
+        when(meterStat.getPacketInCount()).thenReturn(BigInteger.ONE);
+
+        final GetMeterStatisticsOutput output = service.buildReply(input, true);
+        assertTrue(output.getMeterStats().size() > 0);
+
+        final org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats stats =
+                output.getMeterStats().get(0);
+
+        assertEquals(stats.getMeterId().getValue(), METER_NO);
+    }
+
+    @Override
+    public void testStoreStatistics() throws Exception {
+        final org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats stat = mock(org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats.class);
+        when(stat.getMeterId()).thenReturn(new MeterId(METER_NO));
+
+        final List<org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats> stats = Arrays.asList(stat);
+        final GetMeterStatisticsOutput output = mock(GetMeterStatisticsOutput.class);
+        when(output.getMeterStats()).thenReturn(stats);
+
+        service.storeStatistics(output);
+        verify(deviceContext).writeToTransactionWithParentsSlow(eq(LogicalDatastoreType.OPERATIONAL), any(), any());
+    }
+}
\ No newline at end of file
diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/NodeConnectorDirectStatisticsServiceTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/NodeConnectorDirectStatisticsServiceTest.java
new file mode 100644 (file)
index 0000000..9296347
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetNodeConnectorStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetNodeConnectorStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyPortStatsCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.port.stats._case.MultipartReplyPortStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.port.stats._case.multipart.reply.port.stats.PortStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestPortStatsCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.port.stats._case.MultipartRequestPortStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class NodeConnectorDirectStatisticsServiceTest extends AbstractDirectStatisticsServiceTest {
+    private NodeConnectorDirectStatisticsService service;
+
+    @Override
+    public void setUp() throws Exception {
+        service = new NodeConnectorDirectStatisticsService(requestContextStack, deviceContext);
+    }
+
+    @Override
+    public void testBuildRequestBody() throws Exception {
+        final GetNodeConnectorStatisticsInput input = mock(GetNodeConnectorStatisticsInput.class);
+
+        when(input.getNode()).thenReturn(createNodeRef(NODE_ID));
+        when(input.getNodeConnectorId()).thenReturn(nodeConnectorId);
+
+        final MultipartRequestPortStatsCase body = (MultipartRequestPortStatsCase) service.buildRequestBody(input);
+        final MultipartRequestPortStats nodeConnector = body.getMultipartRequestPortStats();
+
+        assertEquals(PORT_NO, nodeConnector.getPortNo());
+    }
+
+    @Override
+    public void testBuildReply() throws Exception {
+        final MultipartReply reply = mock(MultipartReply.class);
+        final MultipartReplyPortStatsCase nodeConnectorCase = mock(MultipartReplyPortStatsCase.class);
+        final MultipartReplyPortStats nodeConnector = mock(MultipartReplyPortStats.class);
+        final PortStats nodeConnectorStat = mock(PortStats.class);
+        final List<PortStats> nodeConnectorStats = Arrays.asList(nodeConnectorStat);
+        final List<MultipartReply> input = Arrays.asList(reply);
+
+        when(nodeConnector.getPortStats()).thenReturn(nodeConnectorStats);
+        when(nodeConnectorCase.getMultipartReplyPortStats()).thenReturn(nodeConnector);
+        when(reply.getMultipartReplyBody()).thenReturn(nodeConnectorCase);
+
+        when(nodeConnectorStat.getPortNo()).thenReturn(PORT_NO);
+        when(nodeConnectorStat.getTxBytes()).thenReturn(BigInteger.ONE);
+        when(nodeConnectorStat.getCollisions()).thenReturn(BigInteger.ONE);
+        when(nodeConnectorStat.getRxBytes()).thenReturn(BigInteger.ONE);
+        when(nodeConnectorStat.getRxCrcErr()).thenReturn(BigInteger.ONE);
+        when(nodeConnectorStat.getRxDropped()).thenReturn(BigInteger.ONE);
+        when(nodeConnectorStat.getRxErrors()).thenReturn(BigInteger.ONE);
+        when(nodeConnectorStat.getRxFrameErr()).thenReturn(BigInteger.ONE);
+        when(nodeConnectorStat.getRxOverErr()).thenReturn(BigInteger.ONE);
+        when(nodeConnectorStat.getRxPackets()).thenReturn(BigInteger.ONE);
+        when(nodeConnectorStat.getTxDropped()).thenReturn(BigInteger.ONE);
+        when(nodeConnectorStat.getTxErrors()).thenReturn(BigInteger.ONE);
+
+        final GetNodeConnectorStatisticsOutput output = service.buildReply(input, true);
+        assertTrue(output.getNodeConnectorStatisticsAndPortNumberMap().size() > 0);
+
+        final NodeConnectorStatisticsAndPortNumberMap stats =
+                output.getNodeConnectorStatisticsAndPortNumberMap().get(0);
+
+        assertEquals(stats.getNodeConnectorId(), nodeConnectorId);
+    }
+
+    @Override
+    public void testStoreStatistics() throws Exception {
+        final NodeConnectorStatisticsAndPortNumberMap stat = mock(NodeConnectorStatisticsAndPortNumberMap.class);
+        when(stat.getNodeConnectorId()).thenReturn(nodeConnectorId);
+
+        final List<NodeConnectorStatisticsAndPortNumberMap> stats = Arrays.asList(stat);
+        final GetNodeConnectorStatisticsOutput output = mock(GetNodeConnectorStatisticsOutput.class);
+        when(output.getNodeConnectorStatisticsAndPortNumberMap()).thenReturn(stats);
+
+        service.storeStatistics(output);
+        verify(deviceContext).writeToTransactionWithParentsSlow(eq(LogicalDatastoreType.OPERATIONAL), any(), any());
+    }
+}
\ No newline at end of file
diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/OpendaylightDirectStatisticsServiceImplTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/OpendaylightDirectStatisticsServiceImplTest.java
new file mode 100644 (file)
index 0000000..c3a2c26
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetFlowStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetFlowStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetGroupStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetGroupStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetMeterStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetMeterStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetNodeConnectorStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetNodeConnectorStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetQueueStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetQueueStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.OpendaylightDirectStatisticsService;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+@RunWith(MockitoJUnitRunner.class)
+public class OpendaylightDirectStatisticsServiceImplTest {
+    @Mock
+    FlowDirectStatisticsService flowDirectStatisticsService;
+    @Mock
+    GroupDirectStatisticsService groupDirectStatisticsService;
+    @Mock
+    MeterDirectStatisticsService meterDirectStatisticsService;
+    @Mock
+    NodeConnectorDirectStatisticsService nodeConnectorDirectStatisticsService;
+    @Mock
+    QueueDirectStatisticsService queueDirectStatisticsService;
+
+    @Mock
+    GetGroupStatisticsInput getGroupStatisticsInput;
+    @Mock
+    GetQueueStatisticsInput getQueueStatisticsInput;
+    @Mock
+    GetFlowStatisticsInput getFlowStatisticsInput;
+    @Mock
+    GetMeterStatisticsInput getMeterStatisticsInput;
+    @Mock
+    GetNodeConnectorStatisticsInput getNodeConnectorStatisticsInput;
+    
+    private OpendaylightDirectStatisticsService service;
+    private OpendaylightDirectStatisticsService emptyService;
+
+    @Before
+    public void setUp() throws Exception {
+        final OpendaylightDirectStatisticsServiceProvider provider = new OpendaylightDirectStatisticsServiceProvider();
+        provider.register(FlowDirectStatisticsService.class, flowDirectStatisticsService);
+        provider.register(GroupDirectStatisticsService.class, groupDirectStatisticsService);
+        provider.register(MeterDirectStatisticsService.class, meterDirectStatisticsService);
+        provider.register(NodeConnectorDirectStatisticsService.class, nodeConnectorDirectStatisticsService);
+        provider.register(QueueDirectStatisticsService.class, queueDirectStatisticsService);
+
+        service = new OpendaylightDirectStatisticsServiceImpl(provider);
+        emptyService = new OpendaylightDirectStatisticsServiceImpl(new OpendaylightDirectStatisticsServiceProvider());
+    }
+
+    @Test
+    public void testGetGroupStatistics() throws Exception {
+        service.getGroupStatistics(getGroupStatisticsInput);
+        verify(groupDirectStatisticsService).handleAndReply(getGroupStatisticsInput);
+    }
+
+    @Test
+    public void testGetGroupStatisticsFail() throws Exception {
+        RpcResult<GetGroupStatisticsOutput> result = emptyService
+                .getGroupStatistics(getGroupStatisticsInput)
+                .get();
+
+        assertFalse(result.isSuccessful());
+
+        for (RpcError error : result.getErrors()) {
+            assertTrue(error.getMessage().contains(GroupDirectStatisticsService.class.getSimpleName()));
+        }
+
+        verify(groupDirectStatisticsService, times(0)).handleAndReply(getGroupStatisticsInput);
+    }
+
+    @Test
+    public void testGetQueueStatistics() throws Exception {
+        service.getQueueStatistics(getQueueStatisticsInput);
+        verify(queueDirectStatisticsService).handleAndReply(getQueueStatisticsInput);
+    }
+
+    @Test
+    public void testGetQueueStatisticsFail() throws Exception {
+        RpcResult<GetQueueStatisticsOutput> result = emptyService
+                .getQueueStatistics(getQueueStatisticsInput)
+                .get();
+
+        assertFalse(result.isSuccessful());
+
+        for (RpcError error : result.getErrors()) {
+            assertTrue(error.getMessage().contains(QueueDirectStatisticsService.class.getSimpleName()));
+        }
+
+        verify(queueDirectStatisticsService, times(0)).handleAndReply(getQueueStatisticsInput);
+    }
+
+    @Test
+    public void testGetFlowStatistics() throws Exception {
+        service.getFlowStatistics(getFlowStatisticsInput);
+        verify(flowDirectStatisticsService).handleAndReply(getFlowStatisticsInput);
+    }
+
+    @Test
+    public void testGetFlowStatisticsFail() throws Exception {
+        RpcResult<GetFlowStatisticsOutput> result = emptyService
+                .getFlowStatistics(getFlowStatisticsInput)
+                .get();
+
+        assertFalse(result.isSuccessful());
+
+        for (RpcError error : result.getErrors()) {
+            assertTrue(error.getMessage().contains(FlowDirectStatisticsService.class.getSimpleName()));
+        }
+
+        verify(flowDirectStatisticsService, times(0)).handleAndReply(getFlowStatisticsInput);
+    }
+
+    @Test
+    public void testGetMeterStatistics() throws Exception {
+        service.getMeterStatistics(getMeterStatisticsInput);
+        verify(meterDirectStatisticsService).handleAndReply(getMeterStatisticsInput);
+    }
+
+    @Test
+    public void testGetMeterStatisticsFail() throws Exception {
+        RpcResult<GetMeterStatisticsOutput> result = emptyService
+                .getMeterStatistics(getMeterStatisticsInput)
+                .get();
+
+        assertFalse(result.isSuccessful());
+
+        for (RpcError error : result.getErrors()) {
+            assertTrue(error.getMessage().contains(MeterDirectStatisticsService.class.getSimpleName()));
+        }
+
+        verify(meterDirectStatisticsService, times(0)).handleAndReply(getMeterStatisticsInput);
+    }
+
+    @Test
+    public void testGetNodeConnectorStatistics() throws Exception {
+        service.getNodeConnectorStatistics(getNodeConnectorStatisticsInput);
+        verify(nodeConnectorDirectStatisticsService).handleAndReply(getNodeConnectorStatisticsInput);
+    }
+
+    @Test
+    public void testGetNodeConnectorStatisticsFail() throws Exception {
+        RpcResult<GetNodeConnectorStatisticsOutput> result = emptyService
+                .getNodeConnectorStatistics(getNodeConnectorStatisticsInput)
+                .get();
+
+        assertFalse(result.isSuccessful());
+
+        for (RpcError error : result.getErrors()) {
+            assertTrue(error.getMessage().contains(NodeConnectorDirectStatisticsService.class.getSimpleName()));
+        }
+
+        verify(nodeConnectorDirectStatisticsService, times(0)).handleAndReply(getNodeConnectorStatisticsInput);
+    }
+}
\ No newline at end of file
diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/QueueDirectStatisticsServiceTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/QueueDirectStatisticsServiceTest.java
new file mode 100644 (file)
index 0000000..3df2f25
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015 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.openflowplugin.impl.statistics.services.direct;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetQueueStatisticsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetQueueStatisticsOutput;
+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.openflow.protocol.rev130731.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyQueueCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.queue._case.MultipartReplyQueue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.queue._case.multipart.reply.queue.QueueStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestQueueCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.queue._case.MultipartRequestQueue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class QueueDirectStatisticsServiceTest extends AbstractDirectStatisticsServiceTest {
+    static final Long QUEUE_NO = 1L;
+    private QueueDirectStatisticsService service;
+
+    @Override
+    public void setUp() throws Exception {
+        service = new QueueDirectStatisticsService(requestContextStack, deviceContext);
+    }
+
+    @Override
+    public void testBuildRequestBody() throws Exception {
+        final GetQueueStatisticsInput input = mock(GetQueueStatisticsInput.class);
+
+        when(input.getNode()).thenReturn(createNodeRef(NODE_ID));
+        when(input.getQueueId()).thenReturn(new QueueId(QUEUE_NO));
+        when(input.getNodeConnectorId()).thenReturn(new NodeConnectorId(NODE_ID + ":" + PORT_NO));
+
+        final MultipartRequestQueueCase body = (MultipartRequestQueueCase) service.buildRequestBody(input);
+        final MultipartRequestQueue queue = body.getMultipartRequestQueue();
+
+        assertEquals(PORT_NO, queue.getPortNo());
+        assertEquals(QUEUE_NO, queue.getQueueId());
+    }
+
+    @Override
+    public void testBuildReply() throws Exception {
+        final MultipartReply reply = mock(MultipartReply.class);
+        final MultipartReplyQueueCase queueCase = mock(MultipartReplyQueueCase.class);
+        final MultipartReplyQueue queue = mock(MultipartReplyQueue.class);
+        final QueueStats queueStat = mock(QueueStats.class);
+        final List<QueueStats> queueStats = Arrays.asList(queueStat);
+        final List<MultipartReply> input = Arrays.asList(reply);
+
+        when(queue.getQueueStats()).thenReturn(queueStats);
+        when(queueCase.getMultipartReplyQueue()).thenReturn(queue);
+        when(reply.getMultipartReplyBody()).thenReturn(queueCase);
+
+        when(queueStat.getPortNo()).thenReturn(PORT_NO);
+        when(queueStat.getQueueId()).thenReturn(QUEUE_NO);
+        when(queueStat.getTxBytes()).thenReturn(BigInteger.ONE);
+        when(queueStat.getTxErrors()).thenReturn(BigInteger.ONE);
+        when(queueStat.getTxPackets()).thenReturn(BigInteger.ONE);
+
+        final GetQueueStatisticsOutput output = service.buildReply(input, true);
+        assertTrue(output.getQueueIdAndStatisticsMap().size() > 0);
+
+        final QueueIdAndStatisticsMap map = output.getQueueIdAndStatisticsMap().get(0);
+        assertEquals(map.getQueueId().getValue(), QUEUE_NO);
+        assertEquals(map.getNodeConnectorId(), nodeConnectorId);
+    }
+
+    @Override
+    public void testStoreStatistics() throws Exception {
+        final QueueIdAndStatisticsMap map = mock(QueueIdAndStatisticsMap.class);
+        when(map.getQueueId()).thenReturn(new QueueId(QUEUE_NO));
+
+        final List<QueueIdAndStatisticsMap> maps = Arrays.asList(map);
+        final GetQueueStatisticsOutput output = mock(GetQueueStatisticsOutput.class);
+        when(output.getQueueIdAndStatisticsMap()).thenReturn(maps);
+
+        service.storeStatistics(output);
+        verify(deviceContext).writeToTransactionWithParentsSlow(eq(LogicalDatastoreType.OPERATIONAL), any(), any());
+    }
+}
\ No newline at end of file
index 12842a34036ac96733d1484c81e46e9790123717..cf0149cd79ffea230d337755f76834bdb7e5be30 100644 (file)
@@ -32,10 +32,10 @@ import org.opendaylight.yangtools.yang.binding.RpcService;
 public class MdSalRegistrationUtilsTest {
 
     /**
-     * Number of currently registrated services (can be changed) in {@link MdSalRegistrationUtils#registerServices
+     * Number of currently registrated services (can be changed)
      * (RpcContext, DeviceContext)}
      */
-    private static final int NUMBER_OF_RPC_SERVICE_REGISTRATION = 12;
+    private static final int NUMBER_OF_RPC_SERVICE_REGISTRATION = 13;
 
     @Test
     public void registerServiceTest() {