[OpenTAM_DPIS] DPI Statistics Manager & dpis CLI
 - Fixed Thomas Vachuska's comment
   .Removed DpiStatisticsJson.java and related codes for avoiding confusion within package because this does not need anymore.
   .Simplified execute() code and fixed comments in DpiListCommand
   .Added javadocs for public methods and fixed typos
 - Rebased from master 1.8.0-SNAPSHOT, 2016.10.14

 - Upgraded the function and performance.
   .changed List<DpiStatistics> to SortedMap<DpiStatistics>
   .added DpiStatisticsService interfaces to get DpiStatistics by receivedTime
   .added more options of dpis CLI: displays indivisual category by topn
   .and some bug fix

 - Fix javadocs and ONOS style method name.
 - Fix javadocs error.

Change-Id: I07a058e04f63bd9c547a5d605975b214eec0ce1f
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfo.java b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfo.java
new file mode 100644
index 0000000..6d99c0c
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfo.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.
+     */
+    public void setTrafficStatistics(TrafficStatInfo trafficStatistics) {
+        this.trafficStatistics = trafficStatistics;
+    }
+
+    /**
+     * Sets the detected protocols statistic information.
+     */
+    public void setDetectedProtos(List<ProtocolStatInfo> detectedProtos) {
+        this.detectedProtos = detectedProtos;
+    }
+
+    /**
+     * Sets the known flows information.
+     */
+    public void setKnownFlows(List<FlowStatInfo> knownFlows) {
+        this.knownFlows = knownFlows;
+    }
+
+    /**
+     * Sets the unknown flows information.
+     */
+    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/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfoCodec.java b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfoCodec.java
new file mode 100644
index 0000000..d7d3473
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfoCodec.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatistics.java b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatistics.java
new file mode 100644
index 0000000..6e7d199
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatistics.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsCodec.java b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsCodec.java
new file mode 100644
index 0000000..1e1d1f7
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsCodec.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsManagerService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsManagerService.java
new file mode 100644
index 0000000..792c293
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsManagerService.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.
+     *
+     * @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.
+     *
+     * @return the added DpiStatistics object class
+     */
+    DpiStatistics addDpiStatistics(DpiStatistics ds);
+
+}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfo.java b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfo.java
new file mode 100644
index 0000000..591df78
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfo.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.
+     */
+    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.
+     */
+    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/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfoCodec.java b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfoCodec.java
new file mode 100644
index 0000000..d32ff6c
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfoCodec.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfo.java b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfo.java
new file mode 100644
index 0000000..372deff
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfo.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfoCodec.java b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfoCodec.java
new file mode 100644
index 0000000..24ef9fc
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfoCodec.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfo.java b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfo.java
new file mode 100644
index 0000000..e7e4ece
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfo.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.
+     */
+    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/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfoCodec.java b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfoCodec.java
new file mode 100644
index 0000000..7f9ace8
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfoCodec.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/package-info.java b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/package-info.java
new file mode 100644
index 0000000..6ee300c
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/dpi/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/dpi/impl/DpiStatisticsManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/dpi/impl/DpiStatisticsManager.java
new file mode 100644
index 0000000..23cb8b8
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/dpi/impl/DpiStatisticsManager.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.incubator.net.dpi.DpiStatInfo;
+import org.onosproject.incubator.net.dpi.DpiStatistics;
+import org.onosproject.incubator.net.dpi.DpiStatisticsManagerService;
+import org.onosproject.incubator.net.dpi.FlowStatInfo;
+import org.onosproject.incubator.net.dpi.ProtocolStatInfo;
+import org.onosproject.incubator.net.dpi.TrafficStatInfo;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.SortedMap;
+import java.util.TimeZone;
+import java.util.TreeMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static java.lang.Thread.sleep;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * DPI Statistics Manager.
+ */
+@Component(immediate = true)
+@Service
+public class DpiStatisticsManager implements DpiStatisticsManagerService {
+
+    private static ServerSocket serverSocket;
+    private static int port = 11990; // socket server listening port
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    private ApplicationId appId;
+
+    private final ExecutorService dpiListenerThread =
+            Executors.newSingleThreadExecutor(groupedThreads("onos/apps/dpi", "dpi-listener"));
+
+    DpiStatisticsListener dpiStatisticsListener = null;
+
+    // 31*2(month)*24(hour)*3600(second)/5(second)
+    private static final int MAX_DPI_STATISTICS_ENTRY = 1071360;
+
+    private SortedMap<String, DpiStatistics> dpiStatisticsMap =
+            new TreeMap<>(new MapComparator());
+
+    private long convertTimeToLong(String timeString) {
+        long timeLong = 0;
+
+        try {
+            // Time format: yyyy-MM-dd HH:mm:ss, Time Zone: GMT
+            SimpleDateFormat df = new SimpleDateFormat(DATE_FMT, Locale.KOREA);
+            df.setTimeZone(TimeZone.getTimeZone(TIME_ZONE));
+
+             timeLong = df.parse(timeString).getTime();
+        } catch (ParseException e) {
+            log.error("Time parse error! Exception={}", e.toString());
+        }
+
+        return timeLong;
+    }
+
+    private static final String DATE_FMT = "yyyy-MM-dd HH:mm:ss";
+    private static final String TIME_ZONE = "GMT";
+
+    public static final int MAX_DPI_STATISTICS_REQUEST = 100;
+    public static final int MAX_DPI_STATISTICS_TOPN = 100;
+
+    @Activate
+    public void activate(ComponentContext context) {
+        appId = coreService.registerApplication("org.onosproject.dpi");
+
+        dpiStatisticsListener = new DpiStatisticsListener();
+        dpiListenerThread.execute(dpiStatisticsListener);
+
+        log.info("Started", appId.id());
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("Deactivated...");
+        dpiStatisticsListener.stop();
+        dpiListenerThread.shutdown();
+        log.info("Stopped");
+    }
+
+    @Override
+    public DpiStatistics getDpiStatisticsLatest() {
+        if (dpiStatisticsMap.size() > 0) {
+            return dpiStatisticsMap.get(dpiStatisticsMap.firstKey());
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public DpiStatistics getDpiStatisticsLatest(int topnProtocols, int topnFlows) {
+        DpiStatistics ds, topnDs;
+
+        ds = getDpiStatisticsLatest();
+        topnDs = processTopn(ds, topnProtocols, topnFlows);
+
+        return topnDs;
+    }
+
+    @Override
+    public List<DpiStatistics> getDpiStatistics(int lastN) {
+        List<DpiStatistics> dsList = new ArrayList<>();
+        DpiStatistics ds;
+
+        if (lastN > MAX_DPI_STATISTICS_REQUEST) {
+            lastN = MAX_DPI_STATISTICS_REQUEST;
+        }
+
+        SortedMap tempMap = new TreeMap(new MapComparator());
+        tempMap.putAll(dpiStatisticsMap);
+
+        for (int i = 0; i < lastN && i < tempMap.size(); i++) {
+            ds = (DpiStatistics) tempMap.get(tempMap.firstKey());
+            dsList.add(i, new DpiStatistics(ds.receivedTime(), ds.dpiStatInfo()));
+
+            tempMap.remove(tempMap.firstKey());
+        }
+
+        return dsList;
+    }
+
+    @Override
+    public List<DpiStatistics> getDpiStatistics(int lastN, int topnProtocols, int topnFlows) {
+        List<DpiStatistics> dsList;
+        List<DpiStatistics> topnDsList = new ArrayList<>();
+        DpiStatistics ds, topnDs;
+
+        dsList = getDpiStatistics(lastN);
+        for (int i = 0; i < dsList.size(); i++) {
+            ds = dsList.get(i);
+            topnDs = processTopn(ds, topnProtocols, topnFlows);
+            topnDsList.add(i, topnDs);
+        }
+
+        return topnDsList;
+    }
+
+    @Override
+    public DpiStatistics getDpiStatistics(String receivedTime) {
+        DpiStatistics ds;
+
+        if (receivedTime == null) {
+            return null;
+        }
+
+        if (!dpiStatisticsMap.containsKey(receivedTime)) {
+            return null;
+        }
+
+        ds = dpiStatisticsMap.get(receivedTime);
+
+        return ds;
+    }
+
+    @Override
+    public DpiStatistics getDpiStatistics(String receivedTime, int topnProtocols, int topnFlows) {
+        DpiStatistics ds, topnDs;
+
+        ds = getDpiStatistics(receivedTime);
+
+        topnDs = processTopn(ds, topnProtocols, topnFlows);
+
+        return topnDs;
+    }
+
+    @Override
+    public DpiStatistics addDpiStatistics(DpiStatistics ds) {
+        if (ds == null) {
+            return ds;
+        }
+
+        // check the time. The firstKey is lastTime because of descending sorted order
+        if (dpiStatisticsMap.size() > 0) {
+            String lastTime = dpiStatisticsMap.get(dpiStatisticsMap.firstKey()).receivedTime();
+            String inputTime = ds.receivedTime();
+
+            long lastTimeLong = convertTimeToLong(lastTime);
+            long inputTimeLong = convertTimeToLong(inputTime);
+
+            if (lastTimeLong >= inputTimeLong) {
+                return null;
+            }
+        }
+
+        if (dpiStatisticsMap.size() >= MAX_DPI_STATISTICS_ENTRY) {
+            // remove the last (oldest) entry
+            dpiStatisticsMap.remove(dpiStatisticsMap.lastKey());
+        }
+
+        if (dpiStatisticsMap.containsKey(ds.receivedTime())) {
+            log.warn("addDpiStatistics(), {} dpiStatistics is already existing!",
+                      ds.receivedTime());
+            return null;
+        }
+
+        dpiStatisticsMap.put(ds.receivedTime(), ds);
+        log.debug("addDpiStatistics: dpiResultJson data[time={}] is added " +
+                          "into DpiStatisticsMap size={}.",
+                  ds.receivedTime(), dpiStatisticsMap.size());
+
+        return ds;
+    }
+
+    private class MapComparator implements Comparator<String> {
+        @Override
+        public int compare(String rt1, String rt2) {
+            long rt1Long = convertTimeToLong(rt1);
+            long rt2Long = convertTimeToLong(rt2);
+
+            // Descending order
+            if (rt1Long > rt2Long) {
+                return -1;
+            } else if (rt1Long < rt2Long) {
+                return 1;
+            } else {
+                return 0;
+            }
+        }
+    }
+
+    private class ProtocolComparator implements Comparator<ProtocolStatInfo> {
+        @Override
+        public int compare(ProtocolStatInfo p1, ProtocolStatInfo p2) {
+            //Descending order
+            if (p1.bytes() > p2.bytes()) {
+                return -1;
+            } else if (p1.bytes() < p2.bytes()) {
+                return 1;
+            } else {
+                return 0;
+            }
+        }
+    }
+
+    private class FlowComparator implements Comparator<FlowStatInfo> {
+        @Override
+        public int compare(FlowStatInfo f1, FlowStatInfo f2) {
+            // Descending order
+            if (f1.bytes() > f2.bytes()) {
+                return -1;
+            } else if (f1.bytes() < f2.bytes()) {
+                return 1;
+            } else {
+                return 0;
+            }
+        }
+    }
+    private DpiStatistics processTopn(DpiStatistics ds, int topnProtocols, int topnFlows) {
+        if (ds == null) {
+            return null;
+        }
+
+        if (topnProtocols <= 0) {
+            // displays all entries
+            topnProtocols = 0;
+        } else if (topnProtocols > MAX_DPI_STATISTICS_TOPN) {
+            topnProtocols = MAX_DPI_STATISTICS_TOPN;
+        }
+
+        if (topnFlows <= 0) {
+            // displays all entries
+            topnFlows = 0;
+        } else if (topnFlows > MAX_DPI_STATISTICS_TOPN) {
+            topnFlows = MAX_DPI_STATISTICS_TOPN;
+        }
+
+        if (topnProtocols == 0 && topnFlows == 0) {
+            return ds;
+        }
+
+        TrafficStatInfo tsi = ds.dpiStatInfo().trafficStatistics();
+        List<ProtocolStatInfo> psiList;
+        List<FlowStatInfo> kfList;
+        List<FlowStatInfo> ufList;
+
+        List<ProtocolStatInfo> pList = ds.dpiStatInfo().detectedProtos();
+        Collections.sort(pList, new ProtocolComparator());
+        if (topnProtocols > 0 && topnProtocols < pList.size()) {
+            psiList = pList.subList(0, topnProtocols);
+        } else {
+            psiList = pList;
+        }
+
+
+        List<FlowStatInfo> fList = ds.dpiStatInfo().knownFlows();
+        Collections.sort(fList, new FlowComparator());
+        if (topnFlows > 0 && topnFlows < fList.size()) {
+            kfList = fList.subList(0, topnFlows);
+        } else {
+            kfList = fList;
+        }
+
+        fList = ds.dpiStatInfo().unknownFlows();
+        Collections.sort(fList, new FlowComparator());
+        if (topnFlows > 0 && topnFlows < fList.size()) {
+            ufList = fList.subList(0, topnFlows);
+        } else {
+            ufList = fList;
+        }
+
+        DpiStatInfo dsi = new DpiStatInfo();
+        dsi.setTrafficStatistics(tsi);
+        dsi.setDetectedProtos(psiList);
+        dsi.setKnownFlows(kfList);
+        dsi.setUnknownFlows(ufList);
+
+        DpiStatistics retDs = new DpiStatistics(ds.receivedTime(), dsi);
+        return retDs;
+    }
+
+    /**
+     * Receiving DPI Statistics result thread.
+     */
+    private class DpiStatisticsListener implements Runnable {
+        Socket clientSocket = null;
+        BufferedReader in = null;
+        PrintWriter out = null;
+
+        String resultJsonString = null;
+
+        static final int MAX_SLEEP_COUNT = 10;
+        int sleepCount = 0;
+
+        @Override
+        public void run() {
+            log.info("DpiStatisticsListener: Receiving thread started...");
+            receiveDpiResult();
+        }
+
+        public void stop() {
+            try {
+                if (serverSocket != null) {
+                    if (clientSocket != null) {
+                        if (in != null) {
+                            in.close();
+                        }
+                        if (out != null) {
+                            out.close();
+                        }
+                        clientSocket.close();
+                        //log.debug("DpiResultListener: stop(): Socket close() is done...");
+                    }
+                    serverSocket.close();
+                    //log.debug("DpiResultListener: stop(): Server close() is done...");
+                }
+            } catch (Exception e) {
+                log.error("DpiStatisticsListener: stop(): Server Socket closing error, exception={}",
+                          e.toString());
+            }
+            log.debug("DpiStatisticsListener: stop(): stopped...");
+        }
+
+        private void receiveDpiResult() {
+            try {
+                serverSocket = new ServerSocket(port);
+            } catch (Exception e) {
+                log.error("DpiStatisticsListener: ServerSocket listening error from port={} in localhost, exception={}",
+                          port, e.toString());
+                return;
+            }
+
+            try {
+                while (true) {
+                    if (clientSocket == null) {
+                        log.info("DpiStatisticsListener: Waiting for accepting from dpi client...");
+                        clientSocket = serverSocket.accept();
+                        log.info("DpiStatisticsListener: Accepted from dpi client={}",
+                                 clientSocket.getRemoteSocketAddress().toString());
+
+                        in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+                        out = new PrintWriter(clientSocket.getOutputStream(), true); // For disconnecting check!
+
+                        resultJsonString = null;
+                    }
+
+                    sleepCount = 0;
+                    while (!in.ready()) {
+                        sleep(1000); // sleep one second.
+                        if (out.checkError() || ++sleepCount >= MAX_SLEEP_COUNT) {
+                            log.debug("DpiStatisticsListener: server and socket connect is lost...");
+                            in.close();
+                            in = null;
+                            out.close();
+                            out = null;
+                            clientSocket.close();
+                            clientSocket = null;
+
+                            break;
+                        }
+                    }
+
+                    if (in != null) {
+                        resultJsonString = in.readLine();
+
+                        // process the result
+                        log.trace("DpiStatisticsListener: resultJsonString={}", resultJsonString);
+                        processResultJson(resultJsonString);
+                    }
+                }
+            } catch (Exception e) {
+                log.error("DpiStatisticsListener: Exception = {}", e.toString());
+                return;
+            }
+        }
+
+        private void processResultJson(String resultJsonString) {
+            Date tr = new Date(System.currentTimeMillis());
+            SimpleDateFormat df = new SimpleDateFormat(DATE_FMT, Locale.KOREA);
+            df.setTimeZone(TimeZone.getTimeZone(TIME_ZONE));
+
+            String curReceivedTime = new String(df.format(tr));
+            String curResultJson = new String(resultJsonString);
+
+            DpiStatInfo dpiStatInfo;
+            ObjectMapper mapper = new ObjectMapper();
+            try {
+                dpiStatInfo = mapper.readValue(curResultJson, DpiStatInfo.class);
+            } catch (IOException e) {
+                log.error("DpiStatisticsListener: ObjectMapper Exception = {}", e.toString());
+                return;
+            }
+
+            DpiStatistics dpiStatistics = new DpiStatistics(curReceivedTime, dpiStatInfo);
+
+            addDpiStatistics(dpiStatistics);
+        }
+    }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/dpi/impl/package-info.java b/incubator/net/src/main/java/org/onosproject/incubator/net/dpi/impl/package-info.java
new file mode 100644
index 0000000..afc6313
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/dpi/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * Implementation of the dpi statistics service.
+ */
+package org.onosproject.incubator.net.dpi.impl;
\ No newline at end of file