Detangling incubator: virtual nets, tunnels, resource labels, oh my

- virtual networking moved to /apps/virtual; with CLI & REST API
- tunnels and labels moved to /apps/tunnel; with CLI & REST API; UI disabled for now
- protobuf/models moved to /core/protobuf/models
- defunct grpc/rpc registry stuff left under /graveyard
- compile dependencies on /incubator moved to respective modules for compilation
- run-time dependencies will need to be re-tested for dependent apps

- /graveyard will be removed in not-too-distant future

Change-Id: I0a0b995c635487edcf95a352f50dd162186b0b39
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfo.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfo.java
new file mode 100644
index 0000000..afa61f0
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfo.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.dpi;
+
+import java.util.List;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * DPI statistic information.
+ */
+public class DpiStatInfo {
+    TrafficStatInfo trafficStatistics;
+    List<ProtocolStatInfo> detectedProtos;
+    List<FlowStatInfo> knownFlows;
+    List<FlowStatInfo> unknownFlows;
+
+    /**
+     * Constructor for default DpiStatInfo class.
+     */
+    public DpiStatInfo() {
+        this.trafficStatistics = null;
+        this.detectedProtos = null;
+        this.knownFlows = null;
+        this.unknownFlows = null;
+    }
+
+    /**
+     * Constructor for DpiStatistics class specified with trafficStatInfo.
+     *
+     * @param trafficStatistics traffic statistic information
+     */
+    public DpiStatInfo(TrafficStatInfo trafficStatistics) {
+        this.trafficStatistics = trafficStatistics;
+        this.detectedProtos = null;
+        this.knownFlows = null;
+        this.unknownFlows = null;
+    }
+
+    /**
+     * Constructor for DpiStatistics class specified with trafficStatInfo and detectedProtos.
+     *
+     * @param trafficStatistics traffic statistic information
+     * @param detectedProtos detected protocols statistic information
+     */
+    public DpiStatInfo(TrafficStatInfo trafficStatistics,
+                       List<ProtocolStatInfo> detectedProtos) {
+        this.trafficStatistics = trafficStatistics;
+        this.detectedProtos = detectedProtos;
+        this.knownFlows = null;
+        this.unknownFlows = null;
+    }
+
+    /**
+     * Constructor for DpiStatistics class specified with trafficStatInfo, detectedProtos and knownFlows.
+     *
+     * @param trafficStatistics traffic statistic information
+     * @param detectedProtos detected protocols statistic information
+     * @param knownFlows known flows
+     */
+    public DpiStatInfo(TrafficStatInfo trafficStatistics,
+                       List<ProtocolStatInfo> detectedProtos,
+                       List<FlowStatInfo> knownFlows) {
+        this.trafficStatistics = trafficStatistics;
+        this.detectedProtos = detectedProtos;
+        this.knownFlows = knownFlows;
+        this.unknownFlows = null;
+    }
+
+    /**
+     * Constructor for DpiStatistics class specified with trafficStatInfo, detectedProtos, knownFlows and unknownFlows.
+     *
+     * @param trafficStatistics traffic statistic information
+     * @param detectedProtos detected protocols statistic information
+     * @param knownFlows known flows
+     * @param unknownFlows unknown flows
+     */
+    public DpiStatInfo(TrafficStatInfo trafficStatistics,
+                       List<ProtocolStatInfo> detectedProtos,
+                       List<FlowStatInfo> knownFlows,
+                       List<FlowStatInfo> unknownFlows) {
+        this.trafficStatistics = trafficStatistics;
+        this.detectedProtos = detectedProtos;
+        this.knownFlows = knownFlows;
+        this.unknownFlows = unknownFlows;
+    }
+
+    /**
+     * Returns DPI traffic statistic information.
+     *
+     * @return trafficStatistics
+     */
+    public TrafficStatInfo trafficStatistics() {
+        return trafficStatistics;
+    }
+
+    /**
+     * Returns DPI detected protocols statistic information.
+     *
+     * @return detectedProtos
+     */
+    public List<ProtocolStatInfo> detectedProtos() {
+        return detectedProtos;
+    }
+
+    /**
+     * Returns DPI known flows.
+     *
+     * @return knownFlows
+     */
+    public List<FlowStatInfo> knownFlows() {
+        return knownFlows;
+    }
+
+    /**
+     * Returns DPI unknown flows.
+     *
+     * @return unknownFlows
+     */
+    public List<FlowStatInfo> unknownFlows() {
+        return unknownFlows;
+    }
+
+    /**
+     * Sets the traffic statistic information.
+     *
+     * @param trafficStatistics traffic statistics
+     */
+    public void setTrafficStatistics(TrafficStatInfo trafficStatistics) {
+        this.trafficStatistics = trafficStatistics;
+    }
+
+    /**
+     * Sets the detected protocols statistic information.
+     *
+     * @param detectedProtos detected protocols statistics
+     */
+    public void setDetectedProtos(List<ProtocolStatInfo> detectedProtos) {
+        this.detectedProtos = detectedProtos;
+    }
+
+    /**
+     * Sets the known flows information.
+     *
+     * @param knownFlows known flows
+     */
+    public void setKnownFlows(List<FlowStatInfo> knownFlows) {
+        this.knownFlows = knownFlows;
+    }
+
+    /**
+     * Sets the unknown flows information.
+     *
+     * @param unknownFlows unknown flows
+     */
+    public void setUnknownFlows(List<FlowStatInfo> unknownFlows) {
+        this.unknownFlows = unknownFlows;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("trafficStatistics", trafficStatistics)
+                .add("detectedProtos", detectedProtos)
+                .add("knownFlows", knownFlows)
+                .add("unknownFlows", unknownFlows)
+                .toString();
+    }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfoCodec.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfoCodec.java
new file mode 100644
index 0000000..34e246a
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfoCodec.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.dpi;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.IntStream;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of encoder for DpiStatInfo codec.
+ */
+public final class DpiStatInfoCodec extends JsonCodec<DpiStatInfo> {
+
+    private static final String TRAFFIC_STATISTICS = "trafficStatistics";
+    private static final String DETECTED_PROTOS = "detectedProtos";
+    private static final String KNOWN_FLOWS = "knownFlows";
+    private static final String UNKNOWN_FLOWS = "unknownFlows";
+
+    private final Logger log = getLogger(getClass());
+
+    @Override
+    public ObjectNode encode(DpiStatInfo dsi, CodecContext context) {
+        checkNotNull(dsi, "DpiStatInfo cannot be null");
+
+        final ObjectNode result = context.mapper().createObjectNode();
+
+        final JsonCodec<TrafficStatInfo> trafficStatInfoCodec =
+                context.codec(TrafficStatInfo.class);
+
+
+        final TrafficStatInfo tsi = dsi.trafficStatistics();
+        if (tsi != null) {
+            final ObjectNode jsonTrafficStatistics = trafficStatInfoCodec.encode(tsi, context);
+            result.set(TRAFFIC_STATISTICS, jsonTrafficStatistics);
+        }
+
+
+        final List<ProtocolStatInfo> psi = dsi.detectedProtos();
+        if (psi != null) {
+            final ArrayNode jsonDetectedProtos = result.putArray(DETECTED_PROTOS);
+            final JsonCodec<ProtocolStatInfo> protocolStatInfoCodec =
+                    context.codec(ProtocolStatInfo.class);
+
+            for (final ProtocolStatInfo protocolStatInfo : psi) {
+                jsonDetectedProtos.add(protocolStatInfoCodec.encode(protocolStatInfo, context));
+            }
+        }
+
+        List<FlowStatInfo> fsi = dsi.knownFlows();
+        if (fsi != null) {
+            final ArrayNode jsonKnownFlows = result.putArray(KNOWN_FLOWS);
+            final JsonCodec<FlowStatInfo> flowStatInfoCodec =
+                    context.codec(FlowStatInfo.class);
+
+            for (final FlowStatInfo flowStatInfo : fsi) {
+                jsonKnownFlows.add(flowStatInfoCodec.encode(flowStatInfo, context));
+            }
+        }
+
+        fsi = dsi.unknownFlows();
+        if (fsi != null) {
+            final ArrayNode jsonUnknownFlows = result.putArray(UNKNOWN_FLOWS);
+            final JsonCodec<FlowStatInfo> flowStatInfoCodec =
+                    context.codec(FlowStatInfo.class);
+
+            for (final FlowStatInfo flowStatInfo : fsi) {
+                jsonUnknownFlows.add(flowStatInfoCodec.encode(flowStatInfo, context));
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public DpiStatInfo decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        log.debug("trafficStatistics={}, full json={} ", json.get("trafficStatistics"), json);
+        TrafficStatInfo trafficStatInfo = null;
+        ObjectNode tsJson = get(json, TRAFFIC_STATISTICS);
+        if (tsJson != null) {
+            JsonCodec<TrafficStatInfo> trafficStatInfoJsonCodec =
+                    context.codec(TrafficStatInfo.class);
+            trafficStatInfo = trafficStatInfoJsonCodec.decode(tsJson, context);
+        }
+
+        final JsonCodec<ProtocolStatInfo> protocolStatInfoCodec =
+                context.codec(ProtocolStatInfo.class);
+
+        List<ProtocolStatInfo> detectedProtos = new ArrayList<>();
+        JsonNode dpJson = json.get(DETECTED_PROTOS);
+        if (dpJson != null) {
+            IntStream.range(0, dpJson.size())
+                    .forEach(i -> detectedProtos.add(
+                            protocolStatInfoCodec.decode(get(dpJson, i),
+                                                     context)));
+        }
+
+        final JsonCodec<FlowStatInfo> flowStatInfoCodec =
+                context.codec(FlowStatInfo.class);
+
+        List<FlowStatInfo> knownFlows = new ArrayList<>();
+        JsonNode kfJson = json.get(KNOWN_FLOWS);
+        if (kfJson != null) {
+            IntStream.range(0, kfJson.size())
+                    .forEach(i -> knownFlows.add(
+                            flowStatInfoCodec.decode(get(kfJson, i),
+                                                         context)));
+        }
+
+        List<FlowStatInfo> unknownFlows = new ArrayList<>();
+        JsonNode ufJson = json.get(UNKNOWN_FLOWS);
+        if (ufJson != null) {
+            IntStream.range(0, ufJson.size())
+                    .forEach(i -> unknownFlows.add(
+                            flowStatInfoCodec.decode(get(ufJson, i),
+                                                     context)));
+        }
+
+        return new DpiStatInfo(trafficStatInfo,
+                               detectedProtos,
+                               knownFlows,
+                               unknownFlows);
+    }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatistics.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatistics.java
new file mode 100644
index 0000000..e6bb618
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatistics.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.dpi;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * DPI statistics with received time.
+ */
+public class DpiStatistics {
+    private final String receivedTime;
+    private final DpiStatInfo dpiStatInfo;
+
+    /**
+     * Constructor for DpiStatistics class.
+     *
+     * @param receivedTime dpiStatInfo received time
+     * @param dpiStatInfo the dpi statistics info
+     */
+    public DpiStatistics(final String receivedTime, final DpiStatInfo dpiStatInfo) {
+        checkNotNull(receivedTime, "Must specify receivedTime");
+        checkNotNull(dpiStatInfo, "Must specify DpiStatInfo");
+
+        this.receivedTime = receivedTime;
+        this.dpiStatInfo = dpiStatInfo;
+    }
+
+    /**
+     * Returns DPI statistics received time.
+     *
+     * @return receivedTime
+     */
+    public String receivedTime() {
+        return receivedTime;
+    }
+
+    /**
+     * Returns DPI statistics information.
+     *
+     * @return dpiStatInfo
+     */
+    public DpiStatInfo dpiStatInfo() {
+        return dpiStatInfo;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(receivedTime, dpiStatInfo);
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final DpiStatistics other = (DpiStatistics) obj;
+        if (!Objects.equals(this.receivedTime, other.receivedTime)) {
+            return false;
+        }
+        if (!Objects.equals(this.dpiStatInfo, other.dpiStatInfo)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("receivedTime", receivedTime)
+                .add("dpiStatInfo", dpiStatInfo)
+                .toString();
+    }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsCodec.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsCodec.java
new file mode 100644
index 0000000..c448277
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsCodec.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.dpi;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of encoder for DpiStatistics codec.
+ */
+public final class DpiStatisticsCodec extends JsonCodec<DpiStatistics> {
+
+    private static final String RECEIVED_TIME = "receivedTime";
+    private static final String DPI_STATISTICS = "dpiStatistics";
+
+    private final Logger log = getLogger(getClass());
+
+    @Override
+    public ObjectNode encode(DpiStatistics ds, CodecContext context) {
+        checkNotNull(ds, "DpiStatistics cannot be null");
+
+        final ObjectNode result = context.mapper().createObjectNode();
+
+        result.put(RECEIVED_TIME, ds.receivedTime());
+
+        final JsonCodec<DpiStatInfo> dpiStatInfoCodec =
+                context.codec(DpiStatInfo.class);
+
+        final ObjectNode jsonDpiStatInfo = dpiStatInfoCodec.encode(ds.dpiStatInfo(), context);
+        result.set(DPI_STATISTICS, jsonDpiStatInfo);
+
+        return result;
+    }
+
+    @Override
+    public DpiStatistics decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        log.debug("receivedTime={}, full json={} ", json.get("receivedTime"), json);
+        JsonNode receivedTimeJson = json.get(RECEIVED_TIME);
+        String receivedTime = receivedTimeJson == null ? "" : receivedTimeJson.asText();
+
+        final JsonCodec<DpiStatInfo> dpiStatInfoCodec =
+                context.codec(DpiStatInfo.class);
+
+        DpiStatInfo dpiStatInfo =
+                dpiStatInfoCodec.decode(get(json, DPI_STATISTICS), context);
+
+        return new DpiStatistics(receivedTime, dpiStatInfo);
+    }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsManagerService.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsManagerService.java
new file mode 100644
index 0000000..5d03536
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsManagerService.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.dpi;
+
+import java.util.List;
+
+/**
+ * Service for DPI Statistics Service Manager.
+ */
+public interface DpiStatisticsManagerService {
+    /**
+     * Get the latest DpiStatistics in the Store list.
+     *
+     * @return the DpiStatistics object class or null if not exist
+     */
+    DpiStatistics getDpiStatisticsLatest();
+
+    /**
+     * Get the latest DpiStatistics in the Store list.
+     *
+     * @param topnProtocols detected topn protocols, default = 100
+     * @param topnFlows detected topn known and unknown flows , default = 100
+     *
+     * @return the DpiStatistics object class or null if not exist
+     */
+    DpiStatistics getDpiStatisticsLatest(int topnProtocols, int topnFlows);
+
+    /**
+     * Gets the last N(Max = 100) DpiStatistics in the Store list.
+     *
+     * @param lastN maximum number to fetch
+     * @return the List of DpiStatistics object class
+     */
+    List<DpiStatistics> getDpiStatistics(int lastN);
+
+    /**
+     * Gets the last N(Max = 100) DpiStatistics in the Store list.
+     *
+     * @param lastN latest N entries
+     * @param topnProtocols detected topn protocols, default = 100
+     * @param topnFlows detected topn known and unknown flows , default = 100
+     * @return the List of DpiStatistics object class
+     */
+    List<DpiStatistics> getDpiStatistics(int lastN, int topnProtocols, int topnFlows);
+
+    /**
+     * Get the specified receivedTime DpiStatistics in the Store list.
+     *
+     * @param receivedTime receivedTime string with format "yyyy-MM-dd HH:mm:ss"
+     * @return the DpiStatistics object class or null if not exist
+     */
+    DpiStatistics getDpiStatistics(String receivedTime);
+
+    /**
+     * Get the specified receivedTime DpiStatistics in the Store list.
+     *
+     * @param receivedTime receivedTime string with format "yyyy-MM-dd HH:mm:ss"
+     * @param topnProtocols detected topn protocols, default = 100
+     * @param topnFlows detected topn known and unknown flows , default = 100
+     * @return the DpiStatistics object class or null if not exist
+     */
+    DpiStatistics getDpiStatistics(String receivedTime, int topnProtocols, int topnFlows);
+
+    /**
+     * Adds DpiStatistics at the end of the Store list.
+     *
+     * @param ds statistics to add
+     * @return the added DpiStatistics object class
+     */
+    DpiStatistics addDpiStatistics(DpiStatistics ds);
+
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfo.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfo.java
new file mode 100644
index 0000000..bb409db
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfo.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.dpi;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Flow statistic information.
+ */
+public class FlowStatInfo {
+    String protocol;
+    String hostAName;
+    int hostAPort;
+    String hostBName;
+    int hostBPort;
+    int detectedProtocol;
+    String detectedProtocolName;
+    long packets;
+    long bytes;
+    String hostServerName;
+
+    /**
+     * Constructor for default FlowStatInfo class.
+     */
+    public FlowStatInfo() {
+        protocol = "";
+        hostAName = "::";
+        hostAPort = 0;
+        hostBName = "";
+        hostBPort = 0;
+        detectedProtocol = 0;
+        detectedProtocolName = "";
+        packets = 0;
+        bytes = 0;
+
+        hostServerName = "";
+    }
+
+    /**
+     * Constructor for FlowStatInfo class specified with flow statistic parameters.
+     *
+     * @param protocol protocol
+     * @param hostAName host A name
+     * @param hostAPort host A port
+     * @param hostBName host B name
+     * @param hostBPort host B port
+     * @param detectedProtocol detected protocol
+     * @param detectedProtocolName detected protocol name
+     * @param packets packet count
+     * @param bytes byte count
+     */
+    public FlowStatInfo(String protocol, String hostAName, int hostAPort, String hostBName, int hostBPort,
+                        int detectedProtocol, String detectedProtocolName, long packets, long bytes) {
+        this.protocol = protocol;
+        this.hostAName = hostAName;
+        this.hostAPort = hostAPort;
+        this.hostBName = hostBName;
+        this.hostBPort = hostBPort;
+        this.detectedProtocol = detectedProtocol;
+        this.detectedProtocolName = detectedProtocolName;
+        this.packets = packets;
+        this.bytes = bytes;
+
+        hostServerName = "";
+    }
+
+    /**
+     * Constructor for FlowStatInfo class specified with flow statistic parameters and hostServerName.
+     *
+     * @param protocol protocol
+     * @param hostAName host A name
+     * @param hostAPort host A port
+     * @param hostBName host B name
+     * @param hostBPort host B port
+     * @param detectedProtocol detected protocol
+     * @param detectedProtocolName detected protocol name
+     * @param packets packet count
+     * @param bytes byte count
+     * @param hostServerName host server name
+     */
+    public FlowStatInfo(String protocol, String hostAName, int hostAPort, String hostBName, int hostBPort,
+                        int detectedProtocol, String detectedProtocolName, long packets, long bytes,
+                        String hostServerName) {
+        this(protocol, hostAName, hostAPort, hostBName, hostBPort, detectedProtocol, detectedProtocolName,
+             packets, bytes);
+
+        this.hostServerName = hostServerName;
+    }
+
+    /**
+     * Returns DPI flow protocol.
+     *
+     * @return protocol
+     */
+    public String protocol() {
+        return protocol;
+    }
+
+    /**
+     * Returns DPI flow host A name.
+     *
+     * @return hostAName
+     */
+    public String hostAName() {
+        return hostAName;
+    }
+
+    /**
+     * Returns DPI flow host A port.
+     *
+     * @return hostAPort
+     */
+    public int hostAPort() {
+        return hostAPort;
+    }
+
+
+    /**
+     * Returns DPI flow host B name.
+     *
+     * @return hostBName
+     */
+    public String hostBName() {
+        return hostBName;
+    }
+
+    /**
+     * Returns DPI flow host B Port.
+     *
+     * @return hostBPort
+     */
+    public int hostBPort() {
+        return hostBPort;
+    }
+
+    /**
+     * Returns DPI flow detected protocol.
+     *
+     * @return detectedProtocol
+     */
+    public int detectedProtocol() {
+        return detectedProtocol;
+    }
+
+    /**
+     * Returns DPI flow detected protocol name.
+     *
+     * @return detectedProtocolName
+     */
+    public String detectedProtocolName() {
+        return detectedProtocolName;
+    }
+
+    /**
+     * Returns DPI flow packets.
+     *
+     * @return packets
+     */
+    public long packets() {
+        return packets;
+    }
+
+    /**
+     * Returns DPI flow bytes.
+     *
+     * @return bytes
+     */
+    public long bytes() {
+        return bytes;
+    }
+
+    /**
+     * Returns DPI flow host server name.
+     *
+     * @return hostServerName
+     */
+    public String hostServerName() {
+        return hostServerName;
+    }
+
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public void setHostAName(String hostAName) {
+        this.hostAName = hostAName;
+    }
+
+    public void setHostAPort(int hostAPort) {
+        this.hostAPort = hostAPort;
+    }
+
+    public void setHostBName(String hostBName) {
+        this.hostBName = hostBName;
+    }
+
+    public void setHostBPort(int hostBPort) {
+        this.hostBPort = hostBPort;
+    }
+
+    public void setDetectedProtocol(int detectedProtocol) {
+        this.detectedProtocol = detectedProtocol;
+    }
+
+    public void setDetectedProtocolName(String detectedProtocolName) {
+        this.detectedProtocolName = detectedProtocolName;
+    }
+
+    public void setPackets(long packets) {
+        this.packets = packets;
+    }
+
+    public void setBytes(long bytes) {
+        this.bytes = bytes;
+    }
+
+    public void setHostServerName(String hostServerName) {
+        this.hostServerName = hostServerName;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("protocol", protocol)
+                .add("hostAName", hostAName)
+                .add("hostAPort", hostAPort)
+                .add("hostBName", hostBName)
+                .add("hostBPort", hostBPort)
+                .add("detectedProtocol", detectedProtocol)
+                .add("detectedProtocolName", detectedProtocolName)
+                .add("packets", packets)
+                .add("bytes", bytes)
+                .add("hostServerName", hostServerName)
+                .toString();
+    }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfoCodec.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfoCodec.java
new file mode 100644
index 0000000..57a3bad
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfoCodec.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.dpi;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of encoder for FlowStatInfo codec.
+ */
+public final class FlowStatInfoCodec extends JsonCodec<FlowStatInfo> {
+
+    private final Logger log = getLogger(getClass());
+
+    @Override
+    public ObjectNode encode(FlowStatInfo fsi, CodecContext context) {
+        checkNotNull(fsi, "FlowStatInfo cannot be null");
+
+        return context.mapper().createObjectNode()
+                .put("protocol", fsi.protocol())
+                .put("hostAName", fsi.hostAName())
+                .put("hostAPort", fsi.hostAPort())
+                .put("hostBName", fsi.hostBName())
+                .put("hostBPort", fsi.hostBPort())
+                .put("detectedProtocol", fsi.detectedProtocol())
+                .put("detectedProtocolName", fsi.detectedProtocolName())
+                .put("packets", fsi.packets())
+                .put("bytes", fsi.bytes())
+                .put("hostServerName", fsi.hostServerName());
+    }
+
+    @Override
+    public FlowStatInfo decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        log.debug("protocol={}, full json={} ", json.get("protocol"), json);
+        final String protocol = json.get("protocol").asText();
+        final String hostAName = json.get("hostAName").asText();
+        final int hostAPort = json.get("hostAPort").asInt();
+        final String hostBName = json.get("hostBName").asText();
+        final int hostBPort = json.get("hostBPort").asInt();
+        final int detectedProtocol = json.get("detectedProtocol").asInt();
+        final String detectedProtocolName = json.get("detectedProtocolName").asText();
+        final long packets = json.get("packets").asLong();
+        final long bytes = json.get("bytes").asLong();
+        final String hostServerName = json.get("hostServerName").asText();
+
+        return new FlowStatInfo(protocol,
+                                hostAName, hostAPort, hostBName, hostBPort,
+                                detectedProtocol, detectedProtocolName,
+                                packets, bytes, hostServerName);
+    }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfo.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfo.java
new file mode 100644
index 0000000..22ac9a1
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfo.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.dpi;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Protocol statistic information.
+ */
+public class ProtocolStatInfo {
+    String name;
+    String breed;
+    long packets;
+    long bytes;
+    int flows;
+
+    /**
+     * Constructor for default ProtocolStatInfo class.
+     */
+    public ProtocolStatInfo() {
+        name = "";
+        breed = "";
+        packets = 0;
+        bytes = 0;
+        flows = 0;
+    }
+
+    /**
+     * Constructor for ProtocolStatInfo class specified with protocol statistic parameters.
+     *
+     * @param name protocol name
+     * @param breed protocol breed
+     * @param packets protocol packets
+     * @param bytes protocol bytes
+     * @param flows protocol flows
+     */
+    public ProtocolStatInfo(String name, String breed, long packets, long bytes, int flows) {
+        this.name = name;
+        this.breed = breed;
+        this.packets = packets;
+        this.bytes = bytes;
+        this.flows = flows;
+    }
+
+    /**
+     * Returns DPI protocol name.
+     *
+     * @return name
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Returns DPI protocol breed.
+     *
+     * @return breed
+     */
+    public String breed() {
+        return breed;
+    }
+
+    /**
+     * Returns DPI protocol packets.
+     *
+     * @return packets
+     */
+    public long packets() {
+        return packets;
+    }
+
+    /**
+     * Returns DPI protocol bytes.
+     *
+     * @return bytes
+     */
+    public long bytes() {
+        return bytes;
+    }
+
+    /**
+     * Returns DPI protocol flows.
+     *
+     * @return flows
+     */
+    public int flows() {
+        return flows;
+    }
+
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setBreed(String breed) {
+        this.breed = breed;
+    }
+
+    public void setPackets(long packets) {
+        this.packets = packets;
+    }
+
+    public void setBytes(long bytes) {
+        this.bytes = bytes;
+    }
+
+    public void setFlows(int flows) {
+        this.flows = flows;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("name", name)
+                .add("breed", breed)
+                .add("packets", packets)
+                .add("bytes", bytes)
+                .add("flows", flows)
+                .toString();
+    }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfoCodec.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfoCodec.java
new file mode 100644
index 0000000..9469f6c
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfoCodec.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.dpi;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of encoder for ProtocolStatInfo codec.
+ */
+public final class ProtocolStatInfoCodec extends JsonCodec<ProtocolStatInfo> {
+
+    private final Logger log = getLogger(getClass());
+
+    @Override
+    public ObjectNode encode(ProtocolStatInfo psi, CodecContext context) {
+        checkNotNull(psi, "ProtocolStatInfo cannot be null");
+
+        return context.mapper().createObjectNode()
+                .put("name", psi.name())
+                .put("breed", psi.breed())
+                .put("packets", psi.packets())
+                .put("bytes", psi.bytes())
+                .put("flows", psi.flows());
+    }
+
+    @Override
+    public ProtocolStatInfo decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        log.debug("name={}, full json={} ", json.get("name"), json);
+        final String name = json.get("name").asText();
+        final String breed = json.get("breed").asText();
+        final long packets = json.get("packets").asLong();
+        final long bytes = json.get("bytes").asLong();
+        final int flows = json.get("flows").asInt();
+
+        return new ProtocolStatInfo(name, breed, packets, bytes, flows);
+    }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfo.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfo.java
new file mode 100644
index 0000000..57cce19
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfo.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.dpi;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Traffic statistic information.
+ */
+public class TrafficStatInfo {
+    long ethernetBytes;
+    long discardedBytes;
+    long ipPackets;
+    long totalPackets;
+    long ipBytes;
+    int avgPktSize;
+    int uniqueFlows;
+    long tcpPackets;
+    long udpPackets;
+
+    double dpiThroughputPps;
+    double dpiThroughputBps;
+    double trafficThroughputPps;
+    double trafficThroughputBps;
+    double trafficDurationSec;
+    int guessedFlowProtos;
+
+    static final String PPS_STRING = "pps";
+    static final String BPS_STRING = "bps";
+    static final String SEC_STRING = "sec";
+
+    /**
+     * Constructor for default TrafficStatInfo class.
+     */
+    public TrafficStatInfo() {
+        ethernetBytes = 0;
+        discardedBytes = 0;
+        ipPackets = 0;
+        totalPackets = 0;
+        ipBytes = 0;
+        avgPktSize = 0;
+        uniqueFlows = 0;
+        tcpPackets = 0;
+        udpPackets = 0;
+        dpiThroughputPps = 0;
+        dpiThroughputBps = 0;
+        trafficThroughputPps = 0;
+        trafficThroughputBps = 0;
+        trafficDurationSec = 0;
+        guessedFlowProtos = 0;
+    }
+
+    /**
+     * Constructor for TrafficStatInfo class specified with traffic statistic parameters.
+     *
+     * @param ethernetBytes ethernet byte count
+     * @param discardedBytes discarded byte count
+     * @param ipPackets IP packet count
+     * @param totalPackets total packet count
+     * @param ipBytes total IP byte count
+     * @param avgPktSize average packet size
+     * @param uniqueFlows unique flows count
+     * @param tcpPackets TCP packet count
+     * @param udpPackets UDP packet count
+     * @param trafficThroughputPps traffic throughput PPS
+     * @param trafficThroughputBps traffic throughput BPS
+     * @param dpiThroughputPps DPI throughput PPS
+     * @param dpiThroughputBps DPI throughput BPS
+     * @param trafficDurationSec traffic duration in seconds
+     * @param guessedFlowProtos guess flow protocols
+     */
+    public TrafficStatInfo(long ethernetBytes, long discardedBytes, long ipPackets, long totalPackets,
+                           long ipBytes, int avgPktSize, int uniqueFlows, long tcpPackets, long udpPackets,
+                           double dpiThroughputPps, double dpiThroughputBps,
+                           double trafficThroughputPps, double trafficThroughputBps,
+                           double trafficDurationSec, int guessedFlowProtos) {
+        this.ethernetBytes = ethernetBytes;
+        this.discardedBytes = discardedBytes;
+        this.ipPackets = ipPackets;
+        this.totalPackets = totalPackets;
+        this.ipBytes = ipBytes;
+        this.avgPktSize = avgPktSize;
+        this.uniqueFlows = uniqueFlows;
+        this.tcpPackets = tcpPackets;
+        this.udpPackets = udpPackets;
+        this.dpiThroughputPps = dpiThroughputPps;
+        this.dpiThroughputBps = dpiThroughputBps;
+        this.trafficThroughputPps = trafficThroughputPps;
+        this.trafficThroughputBps = trafficThroughputBps;
+        this.trafficDurationSec = trafficDurationSec;
+        this.guessedFlowProtos = guessedFlowProtos;
+    }
+
+    /**
+     * Returns DPI traffic ethernet bytes.
+     *
+     * @return ethernetBytes
+     */
+    public long ethernetBytes() {
+        return ethernetBytes;
+    }
+
+    /**
+     * Returns DPI traffic discarded bytes.
+     *
+     * @return discardedBytes
+     */
+    public long discardedBytes() {
+        return discardedBytes;
+    }
+
+    /**
+     * Returns DPI traffic ip packets.
+     *
+     * @return ipPackets
+     */
+    public long ipPackets() {
+        return ipPackets;
+    }
+
+    /**
+     * Returns DPI traffic total packets.
+     *
+     * @return totalPackets
+     */
+    public long totalPackets() {
+        return totalPackets;
+    }
+
+    /**
+     * Returns DPI traffic ip bytes.
+     *
+     * @return ipBytes
+     */
+    public long ipBytes() {
+        return ipBytes;
+    }
+
+    /**
+     * Returns DPI traffic average packet size.
+     *
+     * @return avgPktSize
+     */
+    public int avgPktSize() {
+        return avgPktSize;
+    }
+
+    /**
+     * Returns DPI traffic the number of unique flows.
+     *
+     * @return uniqueFlows
+     */
+    public int uniqueFlows() {
+        return uniqueFlows;
+    }
+
+    /**
+     * Returns DPI traffic TCP packets.
+     *
+     * @return tcpPackets
+     */
+    public long tcpPackets() {
+        return tcpPackets;
+    }
+
+    /**
+     * Returns DPI traffic UDP packets.
+     *
+     * @return udpPackets
+     */
+    public long udpPackets() {
+        return udpPackets;
+    }
+
+    /**
+     * Returns DPI traffic throughput Pps(Packet per second).
+     *
+     * @return dpiThroughputPps
+     */
+    public double dpiThroughputPps() {
+        return dpiThroughputPps;
+    }
+
+    /**
+     * Returns DPI traffic throughput Bps(Byte per second).
+     *
+     * @return dpiThroughputBps
+     */
+    public double dpiThroughputBps() {
+        return dpiThroughputBps;
+    }
+
+    /**
+     * Returns total traffic throughput Pps(Packet per second).
+     *
+     * @return trafficThroughputPps
+     */
+    public double trafficThroughputPps() {
+        return trafficThroughputPps;
+    }
+
+    /**
+     * Returns total traffic throughput Bps(Byte per second).
+     *
+     * @return trafficThroughputBps
+     */
+    public double trafficThroughputBps() {
+        return trafficThroughputBps;
+    }
+
+    /**
+     * Returns DPI traffic duration second.
+     *
+     * @return trafficDurationSec
+     */
+    public double trafficDurationSec() {
+        return trafficDurationSec;
+    }
+
+    /**
+     * Returns DPI traffic the number of guessed flow protocols.
+     *
+     * @return guessedFlowProtos
+     */
+    public int guessedFlowProtos() {
+        return guessedFlowProtos;
+    }
+
+
+    public void setEthernetBytes(long ethernetBytes) {
+        this.ethernetBytes = ethernetBytes;
+    }
+
+    public void setDiscardedBytes(long discardedBytes) {
+        this.discardedBytes = discardedBytes;
+    }
+
+    public void setIpPackets(long ipPackets) {
+        this.ipPackets = ipPackets;
+    }
+
+    public void setTotalPackets(long totalPackets) {
+        this.totalPackets = totalPackets;
+    }
+
+    public void setIpBytes(long ipBytes) {
+        this.ipBytes = ipBytes;
+    }
+
+    public void setAvgPktSize(int avgPktSize) {
+        this.avgPktSize = avgPktSize;
+    }
+
+    public void setUniqueFlows(int uniqueFlows) {
+        this.uniqueFlows = uniqueFlows;
+    }
+
+    public void setTcpPackets(long tcpPackets) {
+        this.tcpPackets = tcpPackets;
+    }
+
+    public void setUdpPackets(long udpPackets) {
+        this.udpPackets = udpPackets;
+    }
+
+    public void setDpiThroughputPps(double dpiThroughputPps) {
+        this.dpiThroughputPps = dpiThroughputPps;
+    }
+
+    public void setDpiThroughputBps(double dpiThroughputBps) {
+        this.dpiThroughputBps = dpiThroughputBps;
+    }
+
+    public void setTrafficThroughputPps(double trafficThroughputPps) {
+        this.trafficThroughputPps = trafficThroughputPps;
+    }
+
+    public void setTrafficThroughputBps(double trafficThroughputBps) {
+        this.trafficThroughputBps = trafficThroughputBps;
+    }
+
+    public void setTrafficDurationSec(double trafficDurationSec) {
+        this.trafficDurationSec = trafficDurationSec;
+    }
+
+    public void setGuessedFlowProtos(int guessedFlowProtos) {
+        this.guessedFlowProtos = guessedFlowProtos;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("ethernetBytes", ethernetBytes)
+                .add("discardedBytes", discardedBytes)
+                .add("ipPackets", ipPackets)
+                .add("totalPackets", totalPackets)
+                .add("ipBytes", ipBytes)
+                .add("avgPktSize", avgPktSize)
+                .add("uniqueFlows", uniqueFlows)
+                .add("tcpPackets", tcpPackets)
+                .add("udpPackets", udpPackets)
+                .add("dpiThroughputPps", dpiThroughputPps + " " + PPS_STRING)
+                .add("dpiThroughputBps", dpiThroughputBps + " " + BPS_STRING)
+                .add("trafficThroughputPps", trafficThroughputPps + " " + PPS_STRING)
+                .add("trafficThroughputBps", trafficThroughputBps + " " + BPS_STRING)
+                .add("trafficDurationSec", trafficDurationSec + " " + SEC_STRING)
+                .add("guessedFlowProtos", guessedFlowProtos)
+                .toString();
+    }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfoCodec.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfoCodec.java
new file mode 100644
index 0000000..dafe523
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfoCodec.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.dpi;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of encoder for TrafficStatInfo codec.
+ */
+public final class TrafficStatInfoCodec extends JsonCodec<TrafficStatInfo> {
+
+    private final Logger log = getLogger(getClass());
+
+    @Override
+    public ObjectNode encode(TrafficStatInfo tsi, CodecContext context) {
+        checkNotNull(tsi, "TrafficStatInfo cannot be null");
+
+        return context.mapper().createObjectNode()
+                .put("ethernetBytes", tsi.ethernetBytes())
+                .put("discardedBytes", tsi.discardedBytes())
+                .put("ipPackets", tsi.ipPackets())
+                .put("totalPackets", tsi.totalPackets())
+                .put("ipBytes", tsi.ipBytes())
+                .put("avgPktSize", tsi.avgPktSize())
+                .put("uniqueFlows", tsi.uniqueFlows())
+                .put("tcpPackets", tsi.tcpPackets())
+                .put("udpPackets", tsi.udpPackets())
+                .put("dpiThroughputPps", tsi.dpiThroughputPps())
+                .put("dpiThroughputBps", tsi.dpiThroughputBps())
+                .put("trafficThroughputPps", tsi.trafficThroughputPps())
+                .put("trafficThroughputBps", tsi.trafficThroughputBps())
+                .put("trafficDurationSec", tsi.trafficDurationSec())
+                .put("guessedFlowProtos", tsi.guessedFlowProtos());
+    }
+
+    @Override
+    public TrafficStatInfo decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        log.debug("ethernetBytes={}, full json={} ", json.get("ethernetBytes"), json);
+        final Long ethernetBytes = json.get("ethernetBytes").asLong();
+        final Long discardedBytes = json.get("discardedBytes").asLong();
+        final Long ipPackets = json.get("ipPackets").asLong();
+        final Long totalPackets = json.get("totalPackets").asLong();
+        final Long ipBytes = json.get("ipBytes").asLong();
+        final int avgPktSize = json.get("avgPktSize").asInt();
+        final int uniqueFlows = json.get("uniqueFlows").asInt();
+        final Long tcpPackets = json.get("tcpPackets").asLong();
+        final Long udpPackets = json.get("udpPackets").asLong();
+        final double dpiThroughputPps = json.get("dpiThroughputPps").asDouble();
+        final double dpiThroughputBps = json.get("dpiThroughputBps").asDouble();
+        final double trafficThroughputPps = json.get("trafficThroughputPps").asDouble();
+        final double trafficThroughputBps = json.get("trafficThroughputBps").asDouble();
+        final double trafficDurationSec = json.get("trafficDurationSec").asDouble();
+        final int guessedFlowProtos = json.get("guessedFlowProtos").asInt();
+
+        return new TrafficStatInfo(ethernetBytes,
+                                   discardedBytes,
+                                   ipPackets, totalPackets,
+                                   ipBytes, avgPktSize,
+                                   uniqueFlows,
+                                   tcpPackets, udpPackets,
+                                   dpiThroughputPps, dpiThroughputBps,
+                                   trafficThroughputPps, trafficThroughputBps,
+                                   trafficDurationSec,
+                                   guessedFlowProtos);
+    }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/package-info.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/package-info.java
new file mode 100644
index 0000000..3f769b8
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Subsystem for dpi statistics service.
+ */
+package org.onosproject.incubator.net.dpi;
\ No newline at end of file