[VOL-4707] Expose programmed subscribers via REST and move classes and interfaces to the API.

Change-Id: Ibfb9caa48455fd349932297cb9191ee0f0341ffa
Signed-off-by: Gustavo Silva <gsilva@furukawalatam.com>
diff --git a/README.md b/README.md
index 004dde8..190fcbe 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,52 @@
 
 ```
 
+## REST API
+
+The programmed subscribers information is available through REST API.
+
+The list of programmed subscribers can be found in the endpoint "/onos/olt/oltapp/programmed-subscribers", e.g:
+```sh
+curl 'http://localhost:8181/onos/olt/oltapp/programmed-subscribers'
+```
+
+There are filters by device-id and connect point (device-id and port), e.g:
+```sh
+curl 'http://localhost:8181/onos/olt/oltapp/programmed-subscribers/of%3A00000a0a0a0a0a0a'
+curl 'http://localhost:8181/onos/olt/oltapp/programmed-subscribers/of%3A00000a0a0a0a0a0a/257'
+```
+
+These commands will generate a JSON output with a list of programmed subscribers, e.g:
+```sh
+{
+  "entries": [
+    {
+      "location": "of:00000a0a0a0a0a0a/257",
+      "tagInfo": {
+        "uniTagMatch": 0,
+        "ponCTag": 900,
+        "ponSTag": 900,
+        "usPonCTagPriority": -1,
+        "usPonSTagPriority": -1,
+        "dsPonCTagPriority": -1,
+        "dsPonSTagPriority": -1,
+        "technologyProfileId": 64,
+        "upstreamBandwidthProfile": "Default",
+        "downstreamBandwidthProfile": "Default",
+        "upstreamOltBandwidthProfile": "Default",
+        "downstreamOltBandwidthProfile": "Default",
+        "serviceName": "hsia",
+        "enableMacLearning": false,
+        "configuredMacAddress": "A4:23:05:00:00:00",
+        "isDhcpRequired": true,
+        "isIgmpRequired": false,
+        "isPppoeRequired": false
+      }
+    }
+  ]
+}
+```
+
 ## App Design
 
 The `org.opencord.olt` application internal structure reflects the following diagram:
diff --git a/api/pom.xml b/api/pom.xml
index bbfea8e..4a6fa6d 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -32,6 +32,14 @@
         <maven.compiler.source>11</maven.compiler.source>
         <maven.compiler.target>11</maven.compiler.target>
     </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.opencord</groupId>
+            <artifactId>sadis-api</artifactId>
+            <version>${sadis.api.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
     <build>
         <plugins>
             <plugin>
diff --git a/impl/src/main/java/org/opencord/olt/impl/AccessDevicePort.java b/api/src/main/java/org/opencord/olt/AccessDevicePort.java
similarity index 88%
rename from impl/src/main/java/org/opencord/olt/impl/AccessDevicePort.java
rename to api/src/main/java/org/opencord/olt/AccessDevicePort.java
index b6d2213..13275c5 100644
--- a/impl/src/main/java/org/opencord/olt/impl/AccessDevicePort.java
+++ b/api/src/main/java/org/opencord/olt/AccessDevicePort.java
@@ -13,8 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.opencord.olt.impl;
+package org.opencord.olt;
 
+import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Port;
 
@@ -35,7 +36,7 @@
      */
     public AccessDevicePort(Port port) {
         this.cp = ConnectPoint.deviceConnectPoint(port.element().id() + "/" + port.number().toLong());
-        this.name = OltUtils.getPortName(port);
+        this.name = getPortName(port);
     }
 
     /**
@@ -89,4 +90,9 @@
     public int hashCode() {
         return Objects.hash(cp, name);
     }
+
+    private String getPortName(Port port) {
+        String name = port.annotations().value(AnnotationKeys.PORT_NAME);
+        return name == null ? "" : name;
+    }
 }
diff --git a/impl/src/main/java/org/opencord/olt/impl/DiscoveredSubscriber.java b/api/src/main/java/org/opencord/olt/DiscoveredSubscriber.java
similarity index 86%
rename from impl/src/main/java/org/opencord/olt/impl/DiscoveredSubscriber.java
rename to api/src/main/java/org/opencord/olt/DiscoveredSubscriber.java
index 226f1b5..8d837f4 100644
--- a/impl/src/main/java/org/opencord/olt/impl/DiscoveredSubscriber.java
+++ b/api/src/main/java/org/opencord/olt/DiscoveredSubscriber.java
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-package org.opencord.olt.impl;
+package org.opencord.olt;
 
+import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.Device;
 import org.onosproject.net.Port;
 import org.opencord.sadis.SubscriberAndDeviceInformation;
 
 import java.util.Objects;
 
-import static org.opencord.olt.impl.OltUtils.portWithName;
-
 /**
  * Contains a subscriber's information and status for a specific device and port.
  */
@@ -69,7 +68,7 @@
      * @return the port name.
      */
     public String portName() {
-        return OltUtils.getPortName(port);
+        return getPortName(port);
     }
 
     @Override
@@ -100,4 +99,14 @@
     public int hashCode() {
         return Objects.hash(port, device, status, hasSubscriber, subscriberAndDeviceInformation);
     }
+
+    private String portWithName(Port port) {
+        return port.element().id().toString() + '/' +
+                port.number() + '[' +
+                getPortName(port) + ']';
+    }
+    private String getPortName(Port port) {
+        String name = port.annotations().value(AnnotationKeys.PORT_NAME);
+        return name == null ? "" : name;
+    }
 }
diff --git a/api/src/main/java/org/opencord/olt/FlowDirection.java b/api/src/main/java/org/opencord/olt/FlowDirection.java
new file mode 100644
index 0000000..839e967
--- /dev/null
+++ b/api/src/main/java/org/opencord/olt/FlowDirection.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2022-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.opencord.olt;
+
+/**
+ * Enumerates the flow directions.
+ */
+public enum FlowDirection {
+    /**
+     * Upstream direction.
+     */
+    UPSTREAM,
+    /**
+     * Downstream direction.
+     */
+    DOWNSTREAM,
+}
\ No newline at end of file
diff --git a/api/src/main/java/org/opencord/olt/FlowOperation.java b/api/src/main/java/org/opencord/olt/FlowOperation.java
new file mode 100644
index 0000000..3ad25a5
--- /dev/null
+++ b/api/src/main/java/org/opencord/olt/FlowOperation.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022-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.opencord.olt;
+
+/**
+ * Enumerates the flow operations.
+ */
+public enum FlowOperation {
+    /**
+     * Flow addition op.
+     */
+    ADD,
+    /**
+     * Flow removal op.
+     */
+    REMOVE;
+
+    @Override
+    public String toString() {
+        return super.toString().toLowerCase();
+    }
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/opencord/olt/impl/MeterData.java b/api/src/main/java/org/opencord/olt/MeterData.java
similarity index 76%
rename from impl/src/main/java/org/opencord/olt/impl/MeterData.java
rename to api/src/main/java/org/opencord/olt/MeterData.java
index 208383d..510b617 100644
--- a/impl/src/main/java/org/opencord/olt/impl/MeterData.java
+++ b/api/src/main/java/org/opencord/olt/MeterData.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package org.opencord.olt.impl;
+package org.opencord.olt;
 
 import org.onosproject.net.meter.MeterCellId;
 import org.onosproject.net.meter.MeterId;
@@ -30,32 +30,69 @@
     private MeterState meterStatus;
     private String bandwidthProfileName;
 
+    /**
+     * Creates a MeterData for a given cellid, status and bandwidth profile.
+     *
+     * @param meterCellId       the cell id
+     * @param meterStatus       the status
+     * @param bandwidthProfile  the bandwidth profile
+     */
     public MeterData(MeterCellId meterCellId, MeterState meterStatus, String bandwidthProfile) {
         this.meterCellId = meterCellId;
         this.meterStatus = meterStatus;
         this.bandwidthProfileName = bandwidthProfile;
     }
 
+    /**
+     * Sets the meter cell id.
+     *
+     * @param meterCellId the meter cell id.
+     */
     public void setMeterCellId(MeterCellId meterCellId) {
         this.meterCellId = meterCellId;
     }
 
+    /**
+     * Sets the meter status.
+     *
+     * @param meterStatus the meter status.
+     */
     public void setMeterStatus(MeterState meterStatus) {
         this.meterStatus = meterStatus;
     }
 
+    /**
+     * Gets the meter id.
+     *
+     * @return Meter id.
+     */
     public MeterId getMeterId() {
         return (MeterId) meterCellId;
     }
 
+    /**
+     * Gets the meter cell id.
+     *
+     * @return Meter cell id.
+     */
     public MeterCellId getMeterCellId() {
         return meterCellId;
     }
 
+    /**
+     * Gets the meter status.
+     *
+     * @return Meter status.
+     */
     public MeterState getMeterStatus() {
         return meterStatus;
     }
 
+    /**
+     * Gets the bandwidth profile name.
+     *
+     * @return Bandwidth profile name.
+     */
     public String getBandwidthProfileName() {
         return bandwidthProfileName;
     }
diff --git a/impl/src/main/java/org/opencord/olt/impl/OltDeviceServiceInterface.java b/api/src/main/java/org/opencord/olt/OltDeviceServiceInterface.java
similarity index 97%
rename from impl/src/main/java/org/opencord/olt/impl/OltDeviceServiceInterface.java
rename to api/src/main/java/org/opencord/olt/OltDeviceServiceInterface.java
index e8fcccb..d6a4827 100644
--- a/impl/src/main/java/org/opencord/olt/impl/OltDeviceServiceInterface.java
+++ b/api/src/main/java/org/opencord/olt/OltDeviceServiceInterface.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package org.opencord.olt.impl;
+package org.opencord.olt;
 
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
diff --git a/impl/src/main/java/org/opencord/olt/impl/OltFlowServiceInterface.java b/api/src/main/java/org/opencord/olt/OltFlowServiceInterface.java
similarity index 96%
rename from impl/src/main/java/org/opencord/olt/impl/OltFlowServiceInterface.java
rename to api/src/main/java/org/opencord/olt/OltFlowServiceInterface.java
index b00594f..c28d63b 100644
--- a/impl/src/main/java/org/opencord/olt/impl/OltFlowServiceInterface.java
+++ b/api/src/main/java/org/opencord/olt/OltFlowServiceInterface.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package org.opencord.olt.impl;
+package org.opencord.olt;
 
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
@@ -52,7 +52,7 @@
      * @param port the NNI port
      * @param action the operatio, ADD or REMOVE.
      */
-    void handleNniFlows(Device device, Port port, OltFlowService.FlowOperation action);
+    void handleNniFlows(Device device, Port port, FlowOperation action);
 
     /**
      * Checks if the default eapol flow is already installed.
diff --git a/api/src/main/java/org/opencord/olt/OltFlowsStatus.java b/api/src/main/java/org/opencord/olt/OltFlowsStatus.java
new file mode 100644
index 0000000..b002d57
--- /dev/null
+++ b/api/src/main/java/org/opencord/olt/OltFlowsStatus.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022-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.opencord.olt;
+/**
+ * Enumerates the flow status.
+ */
+public enum OltFlowsStatus {
+    /**
+     * None status.
+     */
+    NONE,
+    /**
+     * Flow is pending add.
+     */
+    PENDING_ADD,
+    /**
+     * Flow is added.
+     */
+    ADDED,
+    /**
+     * Flow is pending remove.
+     */
+    PENDING_REMOVE,
+    /**
+     * Flow is removed.
+     */
+    REMOVED,
+    /**
+     * An error occurred.
+     */
+    ERROR
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/opencord/olt/impl/OltMeterServiceInterface.java b/api/src/main/java/org/opencord/olt/OltMeterServiceInterface.java
similarity index 98%
rename from impl/src/main/java/org/opencord/olt/impl/OltMeterServiceInterface.java
rename to api/src/main/java/org/opencord/olt/OltMeterServiceInterface.java
index 16d78ef..14cd0c5 100644
--- a/impl/src/main/java/org/opencord/olt/impl/OltMeterServiceInterface.java
+++ b/api/src/main/java/org/opencord/olt/OltMeterServiceInterface.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package org.opencord.olt.impl;
+package org.opencord.olt;
 
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.meter.MeterId;
diff --git a/impl/src/main/java/org/opencord/olt/impl/OltPortStatus.java b/api/src/main/java/org/opencord/olt/OltPortStatus.java
similarity index 72%
rename from impl/src/main/java/org/opencord/olt/impl/OltPortStatus.java
rename to api/src/main/java/org/opencord/olt/OltPortStatus.java
index 3ef348a..6c2c908 100644
--- a/impl/src/main/java/org/opencord/olt/impl/OltPortStatus.java
+++ b/api/src/main/java/org/opencord/olt/OltPortStatus.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package org.opencord.olt.impl;
+package org.opencord.olt;
 
 import java.util.Objects;
 
@@ -23,19 +23,28 @@
  */
 public class OltPortStatus {
     // TODO consider adding a lastUpdated field, it may help with debugging
-    public OltFlowService.OltFlowsStatus defaultEapolStatus;
-    public OltFlowService.OltFlowsStatus subscriberEapolStatus;
-    public OltFlowService.OltFlowsStatus subscriberFlowsStatus;
+    public OltFlowsStatus defaultEapolStatus;
+    public OltFlowsStatus subscriberEapolStatus;
+    public OltFlowsStatus subscriberFlowsStatus;
     // NOTE we need to keep track of the DHCP status as that is installed before the other flows
     // if macLearning is enabled (DHCP is needed to learn the MacAddress from the host)
-    public OltFlowService.OltFlowsStatus dhcpStatus;
-    public OltFlowService.OltFlowsStatus pppoeStatus;
+    public OltFlowsStatus dhcpStatus;
+    public OltFlowsStatus pppoeStatus;
 
-    public OltPortStatus(OltFlowService.OltFlowsStatus defaultEapolStatus,
-                         OltFlowService.OltFlowsStatus subscriberEapolStatus,
-                         OltFlowService.OltFlowsStatus subscriberFlowsStatus,
-                         OltFlowService.OltFlowsStatus dhcpStatus,
-                         OltFlowService.OltFlowsStatus pppoeStatus) {
+    /**
+     * Creates a OltPortStatus from a group of OltFlowsStatus.
+     *
+     * @param defaultEapolStatus     the default
+     * @param subscriberEapolStatus  the status
+     * @param subscriberFlowsStatus  the bandwidth profile
+     * @param dhcpStatus             the bandwidth profile
+     * @param pppoeStatus            the bandwidth profile
+     */
+    public OltPortStatus(OltFlowsStatus defaultEapolStatus,
+                         OltFlowsStatus subscriberEapolStatus,
+                         OltFlowsStatus subscriberFlowsStatus,
+                         OltFlowsStatus dhcpStatus,
+                         OltFlowsStatus pppoeStatus) {
         this.defaultEapolStatus = defaultEapolStatus;
         this.subscriberEapolStatus = subscriberEapolStatus;
         this.subscriberFlowsStatus = subscriberFlowsStatus;
diff --git a/impl/src/main/java/org/opencord/olt/impl/ServiceKey.java b/api/src/main/java/org/opencord/olt/ServiceKey.java
similarity index 97%
rename from impl/src/main/java/org/opencord/olt/impl/ServiceKey.java
rename to api/src/main/java/org/opencord/olt/ServiceKey.java
index c878062..07089e4 100644
--- a/impl/src/main/java/org/opencord/olt/impl/ServiceKey.java
+++ b/api/src/main/java/org/opencord/olt/ServiceKey.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package org.opencord.olt.impl;
+package org.opencord.olt;
 
 import org.opencord.sadis.UniTagInformation;
 
@@ -27,6 +27,7 @@
     private AccessDevicePort port;
     private UniTagInformation service;
 
+
     public ServiceKey(AccessDevicePort port, UniTagInformation service) {
         this.port = port;
         this.service = service;
diff --git a/impl/src/main/java/org/opencord/olt/cli/OltUniPortCompleter.java b/impl/src/main/java/org/opencord/olt/cli/OltUniPortCompleter.java
index 98301db..bda36b6 100644
--- a/impl/src/main/java/org/opencord/olt/cli/OltUniPortCompleter.java
+++ b/impl/src/main/java/org/opencord/olt/cli/OltUniPortCompleter.java
@@ -22,7 +22,7 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceService;
-import org.opencord.olt.impl.OltDeviceServiceInterface;
+import org.opencord.olt.OltDeviceServiceInterface;
 
 import java.util.Collections;
 import java.util.List;
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowMeterMappings.java b/impl/src/main/java/org/opencord/olt/cli/ShowMeterMappings.java
index 7e2175d..9d0e2ad 100644
--- a/impl/src/main/java/org/opencord/olt/cli/ShowMeterMappings.java
+++ b/impl/src/main/java/org/opencord/olt/cli/ShowMeterMappings.java
@@ -20,8 +20,8 @@
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.DeviceId;
-import org.opencord.olt.impl.MeterData;
-import org.opencord.olt.impl.OltMeterServiceInterface;
+import org.opencord.olt.MeterData;
+import org.opencord.olt.OltMeterServiceInterface;
 
 import java.util.Map;
 /**
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowPortStatus.java b/impl/src/main/java/org/opencord/olt/cli/ShowPortStatus.java
index f3b35a0..d82ec33 100644
--- a/impl/src/main/java/org/opencord/olt/cli/ShowPortStatus.java
+++ b/impl/src/main/java/org/opencord/olt/cli/ShowPortStatus.java
@@ -25,9 +25,9 @@
 import org.onosproject.cli.net.PortNumberCompleter;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
-import org.opencord.olt.impl.OltFlowServiceInterface;
-import org.opencord.olt.impl.OltPortStatus;
-import org.opencord.olt.impl.ServiceKey;
+import org.opencord.olt.OltFlowServiceInterface;
+import org.opencord.olt.OltPortStatus;
+import org.opencord.olt.ServiceKey;
 import org.opencord.sadis.UniTagInformation;
 
 import java.util.HashMap;
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedMeters.java b/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedMeters.java
index da2307e..dbb390e 100644
--- a/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedMeters.java
+++ b/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedMeters.java
@@ -20,8 +20,8 @@
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.DeviceId;
-import org.opencord.olt.impl.MeterData;
-import org.opencord.olt.impl.OltMeterServiceInterface;
+import org.opencord.olt.MeterData;
+import org.opencord.olt.OltMeterServiceInterface;
 
 import java.util.Map;
 /**
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedSubscribersCommand.java b/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedSubscribersCommand.java
index ac8d00d..a32fcc3 100644
--- a/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedSubscribersCommand.java
+++ b/impl/src/main/java/org/opencord/olt/cli/ShowProgrammedSubscribersCommand.java
@@ -24,8 +24,8 @@
 import org.onosproject.cli.net.DeviceIdCompleter;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
-import org.opencord.olt.impl.OltFlowServiceInterface;
-import org.opencord.olt.impl.ServiceKey;
+import org.opencord.olt.OltFlowServiceInterface;
+import org.opencord.olt.ServiceKey;
 import org.opencord.sadis.UniTagInformation;
 
 import java.util.Map;
diff --git a/impl/src/main/java/org/opencord/olt/cli/ShowRequestedSubscribersCommand.java b/impl/src/main/java/org/opencord/olt/cli/ShowRequestedSubscribersCommand.java
index 37ef532..067bc18 100644
--- a/impl/src/main/java/org/opencord/olt/cli/ShowRequestedSubscribersCommand.java
+++ b/impl/src/main/java/org/opencord/olt/cli/ShowRequestedSubscribersCommand.java
@@ -24,8 +24,8 @@
 import org.onosproject.cli.net.DeviceIdCompleter;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
-import org.opencord.olt.impl.OltFlowServiceInterface;
-import org.opencord.olt.impl.ServiceKey;
+import org.opencord.olt.OltFlowServiceInterface;
+import org.opencord.olt.ServiceKey;
 
 import java.util.Map;
 import java.util.Set;
diff --git a/impl/src/main/java/org/opencord/olt/impl/Olt.java b/impl/src/main/java/org/opencord/olt/impl/Olt.java
index 7b9dc75..d744c1e 100644
--- a/impl/src/main/java/org/opencord/olt/impl/Olt.java
+++ b/impl/src/main/java/org/opencord/olt/impl/Olt.java
@@ -38,7 +38,14 @@
 import org.onosproject.store.service.StorageService;
 import org.opencord.olt.AccessDeviceEvent;
 import org.opencord.olt.AccessDeviceListener;
+import org.opencord.olt.AccessDevicePort;
 import org.opencord.olt.AccessDeviceService;
+import org.opencord.olt.DiscoveredSubscriber;
+import org.opencord.olt.OltDeviceServiceInterface;
+import org.opencord.olt.OltFlowServiceInterface;
+import org.opencord.olt.OltMeterServiceInterface;
+import org.opencord.olt.ServiceKey;
+import org.opencord.olt.FlowOperation;
 import org.opencord.sadis.BaseInformationService;
 import org.opencord.sadis.SadisService;
 import org.opencord.sadis.SubscriberAndDeviceInformation;
@@ -879,7 +886,7 @@
 
             if (port.isEnabled()) {
                 if (isNni) {
-                    OltFlowService.FlowOperation action = OltFlowService.FlowOperation.ADD;
+                    FlowOperation action = FlowOperation.ADD;
                     // NOTE the NNI is only disabled if the OLT shuts down (reboot or failure).
                     // In that case the flows are purged anyway, so there's no need to deal with them,
                     // it would actually be counter-productive as the openflow connection is severed and they won't
diff --git a/impl/src/main/java/org/opencord/olt/impl/OltDeviceService.java b/impl/src/main/java/org/opencord/olt/impl/OltDeviceService.java
index b336c28..6b11802 100644
--- a/impl/src/main/java/org/opencord/olt/impl/OltDeviceService.java
+++ b/impl/src/main/java/org/opencord/olt/impl/OltDeviceService.java
@@ -25,6 +25,7 @@
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
+import org.opencord.olt.OltDeviceServiceInterface;
 import org.opencord.sadis.BaseInformationService;
 import org.opencord.sadis.SadisService;
 import org.opencord.sadis.SubscriberAndDeviceInformation;
diff --git a/impl/src/main/java/org/opencord/olt/impl/OltFlowService.java b/impl/src/main/java/org/opencord/olt/impl/OltFlowService.java
index ebe0505..04ea492 100644
--- a/impl/src/main/java/org/opencord/olt/impl/OltFlowService.java
+++ b/impl/src/main/java/org/opencord/olt/impl/OltFlowService.java
@@ -64,6 +64,16 @@
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageService;
+import org.opencord.olt.AccessDevicePort;
+import org.opencord.olt.DiscoveredSubscriber;
+import org.opencord.olt.OltDeviceServiceInterface;
+import org.opencord.olt.OltFlowServiceInterface;
+import org.opencord.olt.OltMeterServiceInterface;
+import org.opencord.olt.OltPortStatus;
+import org.opencord.olt.ServiceKey;
+import org.opencord.olt.OltFlowsStatus;
+import org.opencord.olt.FlowDirection;
+import org.opencord.olt.FlowOperation;
 import org.opencord.olt.impl.fttb.FttbUtils;
 import org.opencord.sadis.BandwidthProfileInformation;
 import org.opencord.sadis.BaseInformationService;
@@ -262,31 +272,6 @@
 
     protected boolean waitForRemoval = WAIT_FOR_REMOVAL_DEFAULT;
 
-    public enum FlowOperation {
-        ADD,
-        REMOVE;
-
-
-        @Override
-        public String toString() {
-            return super.toString().toLowerCase();
-        }
-    }
-
-    public enum FlowDirection {
-        UPSTREAM,
-        DOWNSTREAM,
-    }
-
-    public enum OltFlowsStatus {
-        NONE,
-        PENDING_ADD,
-        ADDED,
-        PENDING_REMOVE,
-        REMOVED,
-        ERROR
-    }
-
     protected InternalFlowListener internalFlowListener;
 
     @Activate
diff --git a/impl/src/main/java/org/opencord/olt/impl/OltFlowServiceUtils.java b/impl/src/main/java/org/opencord/olt/impl/OltFlowServiceUtils.java
index 7099b1b..883c198 100644
--- a/impl/src/main/java/org/opencord/olt/impl/OltFlowServiceUtils.java
+++ b/impl/src/main/java/org/opencord/olt/impl/OltFlowServiceUtils.java
@@ -30,6 +30,7 @@
 import org.onosproject.net.flow.criteria.UdpPortCriterion;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.meter.MeterId;
+import org.opencord.olt.OltFlowsStatus;
 import org.opencord.sadis.UniTagInformation;
 
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -78,18 +79,18 @@
      * @param type FlowRuleEvent type
      * @return OltFlowService.OltFlowsStatus
      */
-    public static OltFlowService.OltFlowsStatus flowRuleStatusToOltFlowStatus(FlowRuleEvent.Type type) {
+    public static OltFlowsStatus flowRuleStatusToOltFlowStatus(FlowRuleEvent.Type type) {
         switch (type) {
             case RULE_ADD_REQUESTED:
-                return OltFlowService.OltFlowsStatus.PENDING_ADD;
+                return OltFlowsStatus.PENDING_ADD;
             case RULE_ADDED:
-                return OltFlowService.OltFlowsStatus.ADDED;
+                return OltFlowsStatus.ADDED;
             case RULE_REMOVE_REQUESTED:
-                return OltFlowService.OltFlowsStatus.PENDING_REMOVE;
+                return OltFlowsStatus.PENDING_REMOVE;
             case RULE_REMOVED:
-                return OltFlowService.OltFlowsStatus.REMOVED;
+                return OltFlowsStatus.REMOVED;
             default:
-                return OltFlowService.OltFlowsStatus.NONE;
+                return OltFlowsStatus.NONE;
         }
     }
 
diff --git a/impl/src/main/java/org/opencord/olt/impl/OltMeterService.java b/impl/src/main/java/org/opencord/olt/impl/OltMeterService.java
index 3c7410b..c6f2709 100644
--- a/impl/src/main/java/org/opencord/olt/impl/OltMeterService.java
+++ b/impl/src/main/java/org/opencord/olt/impl/OltMeterService.java
@@ -39,6 +39,9 @@
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageService;
+import org.opencord.olt.MeterData;
+import org.opencord.olt.OltDeviceServiceInterface;
+import org.opencord.olt.OltMeterServiceInterface;
 import org.opencord.sadis.BandwidthProfileInformation;
 import org.opencord.sadis.BaseInformationService;
 import org.opencord.sadis.SadisService;
diff --git a/impl/src/main/java/org/opencord/olt/impl/OltUtils.java b/impl/src/main/java/org/opencord/olt/impl/OltUtils.java
index 869a01d..45d684e 100644
--- a/impl/src/main/java/org/opencord/olt/impl/OltUtils.java
+++ b/impl/src/main/java/org/opencord/olt/impl/OltUtils.java
@@ -19,15 +19,14 @@
 import org.onlab.packet.VlanId;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.Port;
+import org.opencord.olt.FlowOperation;
 import org.opencord.sadis.SubscriberAndDeviceInformation;
 import org.opencord.sadis.UniTagInformation;
 
-import static org.opencord.olt.impl.OltFlowService.FlowOperation.ADD;
-
 /**
  * Utility class for OLT app.
  */
-final class OltUtils {
+public final class OltUtils {
 
     private OltUtils() {
     }
@@ -37,7 +36,7 @@
      * @param port the port
      * @return the annotated port name
      */
-    static String getPortName(Port port) {
+    public static String getPortName(Port port) {
         String name = port.annotations().value(AnnotationKeys.PORT_NAME);
         return name == null ? "" : name;
     }
@@ -47,18 +46,18 @@
      * @param port the port
      * @return the formatted string
      */
-    static String portWithName(Port port) {
+    public static String portWithName(Port port) {
         return port.element().id().toString() + '/' +
                 port.number() + '[' +
                 getPortName(port) + ']';
     }
 
-    static String flowOpToString(OltFlowService.FlowOperation op) {
-        return op == ADD ? "Adding" : "Removing";
+    public static String flowOpToString(FlowOperation op) {
+        return op == FlowOperation.ADD ? "Adding" : "Removing";
     }
 
-    static String completeFlowOpToString(OltFlowService.FlowOperation op) {
-        return op == ADD ? "Added" : "Removed";
+    public static String completeFlowOpToString(FlowOperation op) {
+        return op == FlowOperation.ADD ? "Added" : "Removed";
     }
 
     /**
@@ -72,7 +71,7 @@
      * @param tpId          Techprofile Id
      * @return UniTagInformation
      */
-    static UniTagInformation getUniTagInformation(SubscriberAndDeviceInformation subInfo, VlanId innerVlan,
+    public static UniTagInformation getUniTagInformation(SubscriberAndDeviceInformation subInfo, VlanId innerVlan,
                                                   VlanId outerVlan, int tpId) {
         UniTagInformation service = null;
         for (UniTagInformation tagInfo : subInfo.uniTagList()) {
diff --git a/impl/src/main/java/org/opencord/olt/impl/ServiceKeySerializer.java b/impl/src/main/java/org/opencord/olt/impl/ServiceKeySerializer.java
index 4035bdd..6e0c85b 100644
--- a/impl/src/main/java/org/opencord/olt/impl/ServiceKeySerializer.java
+++ b/impl/src/main/java/org/opencord/olt/impl/ServiceKeySerializer.java
@@ -23,6 +23,8 @@
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
+import org.opencord.olt.AccessDevicePort;
+import org.opencord.olt.ServiceKey;
 import org.opencord.sadis.UniTagInformation;
 
 /**
diff --git a/impl/src/test/java/org/opencord/olt/impl/OltDeviceListenerTest.java b/impl/src/test/java/org/opencord/olt/impl/OltDeviceListenerTest.java
index 576053a..86bfcd8 100644
--- a/impl/src/test/java/org/opencord/olt/impl/OltDeviceListenerTest.java
+++ b/impl/src/test/java/org/opencord/olt/impl/OltDeviceListenerTest.java
@@ -36,6 +36,8 @@
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.provider.ProviderId;
+import org.opencord.olt.DiscoveredSubscriber;
+import org.opencord.olt.FlowOperation;
 import org.opencord.sadis.BaseInformationService;
 import org.opencord.sadis.SubscriberAndDeviceInformation;
 import org.opencord.sadis.UniTagInformation;
@@ -143,7 +145,7 @@
         // NNI events are straight forward, we can provision the flows directly
         assert olt.eventsQueues.isEmpty();
         verify(olt.oltFlowService, times(1))
-                .handleNniFlows(testDevice, enabledNniPort, OltFlowService.FlowOperation.ADD);
+                .handleNniFlows(testDevice, enabledNniPort, FlowOperation.ADD);
 
         Port disabledNniPort = new OltPort(testDevice, false, PortNumber.portNumber(1048576),
                 DefaultAnnotations.builder().set(AnnotationKeys.PORT_NAME, "nni-1").build());
@@ -153,7 +155,7 @@
         // when the NNI goes down we ignore the event
         assert olt.eventsQueues.isEmpty();
         verify(olt.oltFlowService, never())
-                .handleNniFlows(testDevice, disabledNniPort, OltFlowService.FlowOperation.REMOVE);
+                .handleNniFlows(testDevice, disabledNniPort, FlowOperation.REMOVE);
 
         // if the NNI is removed we ignore the event
         Port removedNniPort = new OltPort(testDevice, true, PortNumber.portNumber(1048576),
@@ -163,7 +165,7 @@
 
         assert olt.eventsQueues.isEmpty();
         verify(olt.oltFlowService, never())
-                .handleNniFlows(testDevice, removedNniPort, OltFlowService.FlowOperation.REMOVE);
+                .handleNniFlows(testDevice, removedNniPort, FlowOperation.REMOVE);
     }
 
     @Test
diff --git a/impl/src/test/java/org/opencord/olt/impl/OltFlowServiceTest.java b/impl/src/test/java/org/opencord/olt/impl/OltFlowServiceTest.java
index 35474b7..94f36a3 100644
--- a/impl/src/test/java/org/opencord/olt/impl/OltFlowServiceTest.java
+++ b/impl/src/test/java/org/opencord/olt/impl/OltFlowServiceTest.java
@@ -63,6 +63,11 @@
 import org.onosproject.net.meter.MeterId;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.store.service.TestStorageService;
+import org.opencord.olt.AccessDevicePort;
+import org.opencord.olt.DiscoveredSubscriber;
+import org.opencord.olt.OltPortStatus;
+import org.opencord.olt.ServiceKey;
+import org.opencord.olt.FlowOperation;
 import org.opencord.olt.impl.fttb.FttbUtils;
 import org.opencord.sadis.BaseInformationService;
 import org.opencord.sadis.SadisService;
@@ -88,12 +93,12 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.onosproject.net.AnnotationKeys.PORT_NAME;
-import static org.opencord.olt.impl.OltFlowService.OltFlowsStatus.ERROR;
-import static org.opencord.olt.impl.OltFlowService.OltFlowsStatus.NONE;
-import static org.opencord.olt.impl.OltFlowService.OltFlowsStatus.ADDED;
-import static org.opencord.olt.impl.OltFlowService.OltFlowsStatus.PENDING_ADD;
-import static org.opencord.olt.impl.OltFlowService.OltFlowsStatus.PENDING_REMOVE;
-import static org.opencord.olt.impl.OltFlowService.OltFlowsStatus.REMOVED;
+import static org.opencord.olt.OltFlowsStatus.ERROR;
+import static org.opencord.olt.OltFlowsStatus.NONE;
+import static org.opencord.olt.OltFlowsStatus.ADDED;
+import static org.opencord.olt.OltFlowsStatus.PENDING_ADD;
+import static org.opencord.olt.OltFlowsStatus.PENDING_REMOVE;
+import static org.opencord.olt.OltFlowsStatus.REMOVED;
 import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_BP_ID_DEFAULT;
 import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_MCAST_SERVICE_NAME;
 import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_MCAST_SERVICE_NAME_DEFAULT;
@@ -294,7 +299,7 @@
                                       DefaultAnnotations.builder().set(PORT_NAME, "name-1").build());
 
         OltPortStatus portStatusAdded = new OltPortStatus(
-                OltFlowService.OltFlowsStatus.ADDED,
+                ADDED,
                 NONE,
                 null,
                 null,
@@ -514,7 +519,7 @@
     @Test
     public void testHandleNniFlowsOnlyLldp() {
         component.enableDhcpOnNni = false;
-        component.handleNniFlows(testDevice, nniPort, OltFlowService.FlowOperation.ADD);
+        component.handleNniFlows(testDevice, nniPort, FlowOperation.ADD);
 
         FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
                 .permit()
@@ -535,7 +540,7 @@
     public void testHandleNniFlowsDhcpV4() {
         component.enableDhcpOnNni = true;
         component.enableDhcpV4 = true;
-        component.handleNniFlows(testDevice, nniPort, OltFlowService.FlowOperation.ADD);
+        component.handleNniFlows(testDevice, nniPort, FlowOperation.ADD);
 
         FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
                 .permit()
@@ -561,7 +566,7 @@
     public void testRemoveNniFlowsDhcpV4() {
         component.enableDhcpOnNni = true;
         component.enableDhcpV4 = true;
-        component.handleNniFlows(testDevice, nniPortDisabled, OltFlowService.FlowOperation.REMOVE);
+        component.handleNniFlows(testDevice, nniPortDisabled, FlowOperation.REMOVE);
 
         FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
                 .deny()
@@ -588,7 +593,7 @@
         component.enableDhcpOnNni = true;
         component.enableDhcpV4 = false;
         component.enableDhcpV6 = true;
-        component.handleNniFlows(testDevice, nniPort, OltFlowService.FlowOperation.ADD);
+        component.handleNniFlows(testDevice, nniPort, FlowOperation.ADD);
 
         FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
                 .permit()
@@ -614,7 +619,7 @@
     public void testHandleNniFlowsIgmp() {
         component.enableDhcpOnNni = false;
         component.enableIgmpOnNni = true;
-        component.handleNniFlows(testDevice, nniPort, OltFlowService.FlowOperation.ADD);
+        component.handleNniFlows(testDevice, nniPort, FlowOperation.ADD);
 
         FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
                 .permit()
@@ -638,7 +643,7 @@
         component.enableDhcpOnNni = false;
         component.enablePppoeOnNni = true;
         component.enablePppoe = true;
-        component.handleNniFlows(testDevice, nniPort, OltFlowService.FlowOperation.ADD);
+        component.handleNniFlows(testDevice, nniPort, FlowOperation.ADD);
 
         FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
                 .permit()
@@ -662,7 +667,7 @@
         component.enableDhcpOnNni = false;
         component.enablePppoeOnNni = true;
         component.enablePppoe = true;
-        component.handleNniFlows(testDevice, nniPortDisabled, OltFlowService.FlowOperation.REMOVE);
+        component.handleNniFlows(testDevice, nniPortDisabled, FlowOperation.REMOVE);
 
         FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
                 .deny()
@@ -789,7 +794,7 @@
                 .add();
 
         component.handleSubscriberDhcpFlows(addedSub.device.id(), addedSub.port,
-                OltFlowService.FlowOperation.ADD, si);
+                FlowOperation.ADD, si);
         verify(component.flowObjectiveService, times(1))
                 .filter(eq(addedSub.device.id()), argThat(new FilteringObjectiveMatcher(expectedFilter)));
     }
@@ -839,7 +844,7 @@
                 .add();
 
         component.handleSubscriberPppoeFlows(addedSub.device.id(), addedSub.port,
-                OltFlowService.FlowOperation.ADD, si);
+                FlowOperation.ADD, si);
         verify(component.flowObjectiveService, times(1))
                 .filter(eq(addedSub.device.id()), argThat(new FilteringObjectiveMatcher(expectedFilter)));
     }
@@ -915,17 +920,17 @@
         doReturn(true).when(oltFlowService).areSubscriberFlowsPendingRemoval(any(), any(), eq(true));
         boolean res = oltFlowService.removeSubscriberFlows(sub, DEFAULT_BP_ID_DEFAULT, DEFAULT_MCAST_SERVICE_NAME);
         verify(oltFlowService, times(1))
-                .handleSubscriberDhcpFlows(deviceId, port, OltFlowService.FlowOperation.REMOVE, si);
+                .handleSubscriberDhcpFlows(deviceId, port, FlowOperation.REMOVE, si);
         verify(oltFlowService, times(1))
-                .handleSubscriberEapolFlows(sub, OltFlowService.FlowOperation.REMOVE, si);
+                .handleSubscriberEapolFlows(sub, FlowOperation.REMOVE, si);
         verify(oltFlowService, times(1))
-                .handleSubscriberDataFlows(device, port, OltFlowService.FlowOperation.REMOVE,
+                .handleSubscriberDataFlows(device, port, FlowOperation.REMOVE,
                         si, DEFAULT_MCAST_SERVICE_NAME);
         verify(oltFlowService, times(1))
-                .handleSubscriberIgmpFlows(sub, OltFlowService.FlowOperation.REMOVE);
+                .handleSubscriberIgmpFlows(sub, FlowOperation.REMOVE);
         verify(oltFlowService, never())
                 .handleEapolFlow(any(), any(), any(),
-                        eq(OltFlowService.FlowOperation.ADD), eq(VlanId.vlanId(OltFlowService.EAPOL_DEFAULT_VLAN)));
+                        eq(FlowOperation.ADD), eq(VlanId.vlanId(OltFlowService.EAPOL_DEFAULT_VLAN)));
         Assert.assertFalse(res);
 
         // then test that if the tagged EAPOL is not there we install the default EAPOL
@@ -935,7 +940,7 @@
         res = oltFlowService.removeSubscriberFlows(sub, DEFAULT_BP_ID_DEFAULT, DEFAULT_MCAST_SERVICE_NAME);
         verify(oltFlowService, times(1))
                 .handleEapolFlow(any(), any(), any(),
-                        eq(OltFlowService.FlowOperation.ADD), eq(VlanId.vlanId(OltFlowService.EAPOL_DEFAULT_VLAN)));
+                        eq(FlowOperation.ADD), eq(VlanId.vlanId(OltFlowService.EAPOL_DEFAULT_VLAN)));
         Assert.assertTrue(res);
     }
 
@@ -1011,7 +1016,7 @@
         when(component.sadisService.getSubscriberInfoService().get(testDevice.serialNumber())).
                 thenReturn(testOltFttbSadis);
 
-        component.handleNniFlows(testDevice, nniPort, OltFlowService.FlowOperation.ADD);
+        component.handleNniFlows(testDevice, nniPort, FlowOperation.ADD);
 
         FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
                 .permit()
@@ -1087,7 +1092,7 @@
                 .add();
 
         component.handleSubscriberDhcpFlows(addedSub.device.id(), addedSub.port,
-                OltFlowService.FlowOperation.ADD, si);
+                FlowOperation.ADD, si);
         verify(component.flowObjectiveService, times(1))
                 .filter(eq(addedSub.device.id()), argThat(new FilteringObjectiveMatcher(expectedFilter)));
     }
@@ -1144,7 +1149,7 @@
                 .add();
 
         component.handleSubscriberDhcpFlows(removedSub.device.id(), removedSub.port,
-                OltFlowService.FlowOperation.REMOVE, si);
+                FlowOperation.REMOVE, si);
         verify(component.flowObjectiveService, times(1))
                 .filter(eq(removedSub.device.id()), argThat(new FilteringObjectiveMatcher(expectedFilter)));
     }
@@ -1251,7 +1256,7 @@
                         .add();
 
                 component.handleSubscriberDataFlows(addedSub.device, addedSub.port,
-                        OltFlowService.FlowOperation.ADD, si, DEFAULT_MCAST_SERVICE_NAME_DEFAULT);
+                        FlowOperation.ADD, si, DEFAULT_MCAST_SERVICE_NAME_DEFAULT);
                 verify(component.flowObjectiveService, times(1))
                         .forward(eq(addedSub.device.id()), eq(expected));
             }
@@ -1371,7 +1376,7 @@
                         .remove();
 
                 component.handleSubscriberDataFlows(removedSub.device, removedSub.port,
-                        OltFlowService.FlowOperation.REMOVE, si, DEFAULT_MCAST_SERVICE_NAME_DEFAULT);
+                        FlowOperation.REMOVE, si, DEFAULT_MCAST_SERVICE_NAME_DEFAULT);
                 verify(component.flowObjectiveService, times(1))
                         .forward(eq(removedSub.device.id()), eq(expected));
             }
@@ -1467,7 +1472,7 @@
                         .add();
 
                 component.handleSubscriberDataFlows(addedSub.device, addedSub.port,
-                        OltFlowService.FlowOperation.ADD, si, DEFAULT_MCAST_SERVICE_NAME_DEFAULT);
+                        FlowOperation.ADD, si, DEFAULT_MCAST_SERVICE_NAME_DEFAULT);
                 verify(component.flowObjectiveService, times(1))
                         .forward(eq(addedSub.device.id()), eq(expected));
             }
@@ -1570,7 +1575,7 @@
                         .remove();
 
                 component.handleSubscriberDataFlows(removedSub.device, removedSub.port,
-                        OltFlowService.FlowOperation.REMOVE, si, DEFAULT_MCAST_SERVICE_NAME_DEFAULT);
+                        FlowOperation.REMOVE, si, DEFAULT_MCAST_SERVICE_NAME_DEFAULT);
                 verify(component.flowObjectiveService, times(1))
                         .forward(eq(removedSub.device.id()), eq(expected));
             }
diff --git a/impl/src/test/java/org/opencord/olt/impl/OltMeterServiceTest.java b/impl/src/test/java/org/opencord/olt/impl/OltMeterServiceTest.java
index a7d653c..8e90a2b 100644
--- a/impl/src/test/java/org/opencord/olt/impl/OltMeterServiceTest.java
+++ b/impl/src/test/java/org/opencord/olt/impl/OltMeterServiceTest.java
@@ -29,6 +29,7 @@
 import org.onosproject.net.meter.MeterState;
 import org.onosproject.store.service.StorageServiceAdapter;
 import org.onosproject.store.service.TestStorageService;
+import org.opencord.olt.MeterData;
 import org.opencord.sadis.SadisService;
 
 import java.util.HashMap;
diff --git a/impl/src/test/java/org/opencord/olt/impl/OltTest.java b/impl/src/test/java/org/opencord/olt/impl/OltTest.java
index d968c24..9197297 100644
--- a/impl/src/test/java/org/opencord/olt/impl/OltTest.java
+++ b/impl/src/test/java/org/opencord/olt/impl/OltTest.java
@@ -39,6 +39,7 @@
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.store.service.TestStorageService;
+import org.opencord.olt.DiscoveredSubscriber;
 import org.opencord.sadis.SadisService;
 import org.opencord.sadis.SubscriberAndDeviceInformation;
 import org.opencord.sadis.UniTagInformation;
diff --git a/pom.xml b/pom.xml
index d04dd41..25c9b99 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,6 +37,7 @@
     <properties>
         <sadis.api.version>5.6.0-SNAPSHOT</sadis.api.version>
         <olt.api.version>5.1.0-SNAPSHOT</olt.api.version>
+        <olt.impl.version>5.1.0-SNAPSHOT</olt.impl.version>
     </properties>
     <dependencies>
         <dependency>
diff --git a/web/pom.xml b/web/pom.xml
index 73f782a..04a397b 100644
--- a/web/pom.xml
+++ b/web/pom.xml
@@ -44,6 +44,12 @@
         </dependency>
         <dependency>
             <groupId>org.opencord</groupId>
+            <artifactId>sadis-api</artifactId>
+            <version>${sadis.api.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opencord</groupId>
             <artifactId>olt-api</artifactId>
             <version>${olt.api.version}</version>
             <scope>compile</scope>
diff --git a/web/src/main/java/org/opencord/olt/rest/OltWebResource.java b/web/src/main/java/org/opencord/olt/rest/OltWebResource.java
index c512304..a074620 100644
--- a/web/src/main/java/org/opencord/olt/rest/OltWebResource.java
+++ b/web/src/main/java/org/opencord/olt/rest/OltWebResource.java
@@ -15,14 +15,19 @@
  */
 package org.opencord.olt.rest;
 
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.onlab.packet.VlanId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.rest.AbstractWebResource;
 import org.opencord.olt.AccessDeviceService;
-import org.slf4j.Logger;
+import org.opencord.olt.OltFlowServiceInterface;
+import org.opencord.olt.ServiceKey;
+import org.opencord.sadis.UniTagInformation;
 
+import org.slf4j.Logger;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -33,7 +38,10 @@
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
 import static org.slf4j.LoggerFactory.getLogger;
@@ -44,8 +52,11 @@
 
 @Path("oltapp")
 public class OltWebResource extends AbstractWebResource {
+    private final ObjectNode root = mapper().createObjectNode();
+    private final ArrayNode node = root.putArray("entries");
     private final Logger log = getLogger(getClass());
-
+    private static final String LOCATION = "location";
+    private static final String TAG_INFO = "tagInfo";
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
@@ -231,4 +242,79 @@
         }
         return Response.noContent().build();
     }
+
+    /**
+     * Gets subscribers programmed in the dataplane.
+     *
+     * @return 200 OK
+     */
+    @GET
+    @Path("programmed-subscribers")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getProgrammedSubscribers() {
+        return getProgrammedSubscribers(null, null);
+    }
+
+    /**
+     * Gets subscribers programmed in the dataplane.
+     *
+     * @param deviceId  device-id to filter the results.
+     *
+     * @return 200 OK
+     */
+    @GET
+    @Path("programmed-subscribers/{deviceId}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getProgrammedSubscribersByDeviceId(@PathParam("deviceId") String deviceId) {
+        return getProgrammedSubscribers(deviceId, null);
+    }
+
+    /*
+     * Gets subscribers programmed in the dataplane.
+     *
+     * @param deviceId  device-id to filter the results.
+     * @param port      port to filter the results.
+     *
+     * @return 200 OK
+     */
+    @GET
+    @Path("programmed-subscribers/{deviceId}/{port}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getProgrammedSubscribersByConnectPoint(@PathParam("deviceId") String deviceId,
+                                                           @PathParam("port") String port) {
+        return getProgrammedSubscribers(deviceId, port);
+    }
+
+    private Response getProgrammedSubscribers(String deviceId, String port) {
+        OltFlowServiceInterface service = get(OltFlowServiceInterface.class);
+        Map<ServiceKey, UniTagInformation> info = service.getProgrammedSubscribers();
+        Set<Map.Entry<ServiceKey, UniTagInformation>> entries = info.entrySet();
+        if (deviceId != null && !deviceId.isEmpty()) {
+            entries = entries.stream().filter(entry -> entry.getKey().getPort().connectPoint().deviceId()
+                    .equals(DeviceId.deviceId(deviceId))).collect(Collectors.toSet());
+        }
+
+        if (port != null && !port.isEmpty()) {
+            PortNumber portNumber = PortNumber.portNumber(port);
+            entries = entries.stream().filter(entry -> entry.getKey().getPort().connectPoint().port()
+                    .equals(portNumber)).collect(Collectors.toSet());
+        }
+
+        try {
+            entries.forEach(entry -> {
+                ConnectPoint location = entry.getKey().getPort().connectPoint();
+                UniTagInformation tagInfo = entry.getValue();
+                ObjectNode encodedTagInfo = codec(UniTagInformation.class).encode(tagInfo, this);
+                ObjectNode encodedEntry = mapper().createObjectNode();
+                encodedEntry.put(LOCATION, location.toString())
+                        .set(TAG_INFO, encodedTagInfo);
+                node.add(encodedEntry);
+            });
+
+            return ok(mapper().writeValueAsString(root)).build();
+        } catch (Exception e) {
+            log.error("Error while fetching programmed subscriber list through REST API: {}", e.getMessage());
+            return Response.status(INTERNAL_SERVER_ERROR).build();
+        }
+    }
 }