Revert "Revert "SEBA-814 To support Multi-Tcont on TT-workflow, SADIS configuration is updated.""

(Re-applying changes after releasing and bumping major version)

This reverts commit e4f4b63f171ffd2ec92ee6e3a3f35e8905bce215.

Change-Id: I7b34c094f95455becffa7fa55d1de9eba55d298a
diff --git a/api/src/main/java/org/opencord/sadis/SubscriberAndDeviceInformation.java b/api/src/main/java/org/opencord/sadis/SubscriberAndDeviceInformation.java
index 28540a0..08ab94e 100644
--- a/api/src/main/java/org/opencord/sadis/SubscriberAndDeviceInformation.java
+++ b/api/src/main/java/org/opencord/sadis/SubscriberAndDeviceInformation.java
@@ -17,22 +17,15 @@
 
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+import java.util.List;
+
 /**
  * Represents a unit of information about a subscriber or access device.
  */
 public class SubscriberAndDeviceInformation extends BaseInformation {
 
-
-    @JsonProperty(value = "sTag")
-    VlanId sTag;
-
-    @JsonProperty(value = "cTag")
-    VlanId cTag;
-
     @JsonProperty(value = "nasPortId")
     String nasPortId;
 
@@ -57,32 +50,10 @@
     @JsonProperty(value = "remoteId")
     String remoteId;
 
-    @JsonProperty(value = "technologyProfileId")
-    int technologyProfileId = -1;
+    @JsonProperty(value = "uniTagList")
+    List<UniTagInformation> uniTagList;
 
-    @JsonProperty(value = "upstreamBandwidthProfile")
-    String upstreamBandwidthProfile;
-
-    @JsonProperty(value = "downstreamBandwidthProfile")
-    String downstreamBandwidthProfile;
-
-    protected SubscriberAndDeviceInformation() {
-    }
-
-    public final VlanId sTag() {
-        return this.sTag;
-    }
-
-    public final void setSTag(final VlanId stag) {
-        this.sTag = stag;
-    }
-
-    public final VlanId cTag() {
-        return this.cTag;
-    }
-
-    public final void setCTag(final VlanId ctag) {
-        this.cTag = ctag;
+    public SubscriberAndDeviceInformation() {
     }
 
     public final String nasPortId() {
@@ -149,29 +120,14 @@
         this.remoteId = remoteId;
     }
 
-    public final int technologyProfileId() {
-        return this.technologyProfileId;
+    public final List<UniTagInformation> uniTagList() {
+        return this.uniTagList;
     }
 
-    public final void setTechnologyProfileId(final int technologyProfileId) {
-        this.technologyProfileId = technologyProfileId;
+    public final void setUniTagList(final List<UniTagInformation> uniTagList) {
+        this.uniTagList = uniTagList;
     }
 
-    public final String upstreamBandwidthProfile() {
-        return this.upstreamBandwidthProfile;
-    }
-
-    public final void setUpstreamBandwidthProfile(final String upstreamBandwidthProfile) {
-        this.upstreamBandwidthProfile = upstreamBandwidthProfile;
-    }
-
-    public final String downstreamBandwidthProfile() {
-        return this.downstreamBandwidthProfile;
-    }
-
-    public final void setDownstreamBandwidthProfile(final String downstreamBandwidthProfile) {
-        this.downstreamBandwidthProfile = downstreamBandwidthProfile;
-    }
 
     /*
      * (non-Javadoc)
@@ -182,22 +138,16 @@
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + (this.cTag == null ? 0 : this.cTag.hashCode());
         result = prime * result + (this.hardwareIdentifier == null ? 0 : this.hardwareIdentifier.hashCode());
         result = prime * result + (this.id == null ? 0 : this.id.hashCode());
         result = prime * result + (this.nasPortId == null ? 0 : this.nasPortId.hashCode());
         result = prime * result + this.uplinkPort;
-        result = prime * result + (this.sTag == null ? 0 : this.sTag.hashCode());
         result = prime * result + this.slot;
         result = prime * result + (this.ipAddress == null ? 0 : this.ipAddress.hashCode());
         result = prime * result + (this.nasId == null ? 0 : this.nasId.hashCode());
         result = prime + result + (this.circuitId == null ? 0 : this.circuitId.hashCode());
         result = prime + result + (this.remoteId == null ? 0 : this.remoteId.hashCode());
-        result = prime + result + this.technologyProfileId;
-        result = prime + result +
-                (this.upstreamBandwidthProfile == null ? 0 : this.upstreamBandwidthProfile.hashCode());
-        result = prime + result +
-                (this.downstreamBandwidthProfile == null ? 0 : this.downstreamBandwidthProfile.hashCode());
+        result = prime + result + (this.uniTagList == null ? 0 : this.uniTagList.hashCode());
         return result;
     }
 
@@ -218,13 +168,7 @@
             return false;
         }
         final SubscriberAndDeviceInformation other = (SubscriberAndDeviceInformation) obj;
-        if (this.cTag == null) {
-            if (other.cTag != null) {
-                return false;
-            }
-        } else if (!this.cTag.equals(other.cTag)) {
-            return false;
-        }
+
         if (this.hardwareIdentifier == null) {
             if (other.hardwareIdentifier != null) {
                 return false;
@@ -263,13 +207,7 @@
         if (this.uplinkPort != other.uplinkPort) {
             return false;
         }
-        if (this.sTag == null) {
-            if (other.sTag != null) {
-                return false;
-            }
-        } else if (!this.sTag.equals(other.sTag)) {
-            return false;
-        }
+
         if (this.slot != other.slot) {
             return false;
         }
@@ -287,21 +225,11 @@
         } else if (!this.remoteId.equals(other.remoteId)) {
             return false;
         }
-        if (this.technologyProfileId != other.technologyProfileId) {
-            return false;
-        }
-        if (this.upstreamBandwidthProfile == null) {
-            if (other.upstreamBandwidthProfile != null) {
+        if (this.uniTagList == null) {
+            if (other.uniTagList != null) {
                 return false;
             }
-        } else if (!this.upstreamBandwidthProfile.equals(other.upstreamBandwidthProfile)) {
-            return false;
-        }
-        if (this.downstreamBandwidthProfile == null) {
-            if (other.downstreamBandwidthProfile != null) {
-                return false;
-            }
-        } else if (!this.downstreamBandwidthProfile.equals(other.downstreamBandwidthProfile)) {
+        } else if (!this.uniTagList.equals(other.uniTagList)) {
             return false;
         }
         return true;
@@ -316,34 +244,16 @@
     public String toString() {
         final StringBuilder buf = new StringBuilder();
         buf.append('[');
-        buf.append("id:");
-        buf.append(this.id);
-        buf.append(",cTag:");
-        buf.append(this.cTag);
-        buf.append(",sTag:");
-        buf.append(this.sTag);
-        buf.append(",nasPortId:");
-        buf.append(this.nasPortId);
-        buf.append(",uplinkPort:");
-        buf.append(this.uplinkPort);
-        buf.append(",slot:");
-        buf.append(this.slot);
-        buf.append(",hardwareIdentifier:");
-        buf.append(this.hardwareIdentifier);
-        buf.append(",ipaddress:");
-        buf.append(this.ipAddress);
-        buf.append(",nasId:");
-        buf.append(this.nasId);
-        buf.append(",circuitId:");
-        buf.append(this.circuitId);
-        buf.append(",remoteId:");
-        buf.append(this.remoteId);
-        buf.append(",technologyProfileId:");
-        buf.append(this.technologyProfileId);
-        buf.append(",upstreamBandwidthProfile:");
-        buf.append(this.upstreamBandwidthProfile);
-        buf.append(",downstreamBandwidthProfile:");
-        buf.append(this.downstreamBandwidthProfile);
+        buf.append("id:").append(this.id);
+        buf.append(",nasPortId:").append(this.nasPortId);
+        buf.append(",uplinkPort:").append(this.uplinkPort);
+        buf.append(",slot:").append(this.slot);
+        buf.append(",hardwareIdentifier:").append(this.hardwareIdentifier);
+        buf.append(",ipaddress:").append(this.ipAddress);
+        buf.append(",nasId:").append(this.nasId);
+        buf.append(",circuitId:").append(this.circuitId);
+        buf.append(",remoteId:").append(this.remoteId);
+        buf.append(",uniTagList:").append(this.uniTagList);
         buf.append(']');
 
         return buf.toString();
diff --git a/api/src/main/java/org/opencord/sadis/UniTagInformation.java b/api/src/main/java/org/opencord/sadis/UniTagInformation.java
new file mode 100644
index 0000000..8bdde45
--- /dev/null
+++ b/api/src/main/java/org/opencord/sadis/UniTagInformation.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2017-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.sadis;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.onlab.packet.VlanId;
+
+/**
+ * Represents a unit of information about a service.
+ */
+public final class UniTagInformation {
+
+    @JsonProperty(value = "uniTagMatch")
+    private VlanId uniTagMatch = VlanId.NONE;
+
+    @JsonProperty(value = "ponCTag")
+    private VlanId ponCTag;
+
+    @JsonProperty(value = "ponSTag")
+    private VlanId ponSTag;
+
+    @JsonProperty(value = "usPonCTagPriority")
+    private int usPonCTagPriority = -1;
+
+    @JsonProperty(value = "usPonSTagPriority")
+    private int usPonSTagPriority = -1;
+
+    @JsonProperty(value = "dsPonCTagPriority")
+    private int dsPonCTagPriority = -1;
+
+    @JsonProperty(value = "dsPonSTagPriority")
+    private int dsPonSTagPriority = -1;
+
+    @JsonProperty(value = "technologyProfileId")
+    private int technologyProfileId = -1;
+
+    @JsonProperty(value = "upstreamBandwidthProfile")
+    private String upstreamBandwidthProfile;
+
+    @JsonProperty(value = "downstreamBandwidthProfile")
+    private String downstreamBandwidthProfile;
+
+    @JsonProperty(value = "serviceName")
+    private String serviceName;
+
+    @JsonProperty(value = "enableMacLearning")
+    private boolean enableMacLearning = false;
+
+    @JsonProperty(value = "configuredMacAddress")
+    private String configuredMacAddress;
+
+    @JsonProperty(value = "isDhcpRequired")
+    private boolean isDhcpRequired;
+
+    @JsonProperty(value = "isIgmpRequired")
+    private boolean isIgmpRequired;
+
+    public UniTagInformation() {
+
+    }
+
+    private UniTagInformation(final VlanId uniTagMatch, final VlanId ponCTag, final VlanId ponSTag,
+                              final int usPonCTagPriority, final int usPonSTagPriority,
+                              final int dsPonCTagPriority, final int dsPonSTagPriority,
+                              final int technologyProfileId,
+                              final String upstreamBandwidthProfile, final String downstreamBandwidthProfile,
+                              final String serviceName, final boolean enableMacLearning,
+                              final String configuredMacAddress, final boolean isDhcpRequired,
+                              final boolean isIgmpRequired) {
+        this.uniTagMatch = uniTagMatch;
+        this.ponCTag = ponCTag;
+        this.ponSTag = ponSTag;
+        this.usPonCTagPriority = usPonCTagPriority;
+        this.usPonSTagPriority = usPonSTagPriority;
+        this.dsPonCTagPriority = dsPonCTagPriority;
+        this.dsPonSTagPriority = dsPonSTagPriority;
+        this.technologyProfileId = technologyProfileId;
+        this.upstreamBandwidthProfile = upstreamBandwidthProfile;
+        this.downstreamBandwidthProfile = downstreamBandwidthProfile;
+        this.serviceName = serviceName;
+        this.enableMacLearning = enableMacLearning;
+        this.configuredMacAddress = configuredMacAddress;
+        this.isDhcpRequired = isDhcpRequired;
+        this.isIgmpRequired = isIgmpRequired;
+    }
+
+    public final VlanId getUniTagMatch() {
+        return uniTagMatch;
+    }
+
+    public final VlanId getPonCTag() {
+        return ponCTag;
+    }
+
+    public final VlanId getPonSTag() {
+        return ponSTag;
+    }
+
+    public final int getUsPonCTagPriority() {
+        return usPonCTagPriority;
+    }
+
+    public final int getUsPonSTagPriority() {
+        return usPonSTagPriority;
+    }
+
+    public final int getDsPonCTagPriority() {
+        return dsPonCTagPriority;
+    }
+
+    public final int getDsPonSTagPriority() {
+        return dsPonSTagPriority;
+    }
+
+    public final int getTechnologyProfileId() {
+        return technologyProfileId;
+    }
+
+    public final String getUpstreamBandwidthProfile() {
+        return upstreamBandwidthProfile;
+    }
+
+    public final String getDownstreamBandwidthProfile() {
+        return downstreamBandwidthProfile;
+    }
+
+    public final String getServiceName() {
+        return serviceName;
+    }
+
+    public final boolean getEnableMacLearning() {
+        return enableMacLearning;
+    }
+
+    public final String getConfiguredMacAddress() {
+        return configuredMacAddress;
+    }
+
+    public final boolean getIsDhcpRequired() {
+        return isDhcpRequired;
+    }
+
+    public final boolean getIsIgmpRequired() {
+        return isIgmpRequired;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        UniTagInformation that = (UniTagInformation) o;
+
+        if (uniTagMatch != that.uniTagMatch) {
+            return false;
+        }
+        if (technologyProfileId != that.technologyProfileId) {
+            return false;
+        }
+        if (ponCTag != that.ponCTag) {
+            return false;
+        }
+        if (ponSTag != that.ponSTag) {
+            return false;
+        }
+        if (usPonCTagPriority != that.usPonCTagPriority) {
+            return false;
+        }
+        if (usPonSTagPriority != that.usPonSTagPriority) {
+            return false;
+        }
+        if (dsPonCTagPriority != that.dsPonCTagPriority) {
+            return false;
+        }
+        if (dsPonSTagPriority != that.dsPonSTagPriority) {
+            return false;
+        }
+        if (enableMacLearning != that.enableMacLearning) {
+            return false;
+        }
+        if (configuredMacAddress != that.configuredMacAddress) {
+            return false;
+        }
+        if (isDhcpRequired != that.isDhcpRequired) {
+            return false;
+        }
+        if (isIgmpRequired != that.isIgmpRequired) {
+            return false;
+        }
+        if (upstreamBandwidthProfile != null ? !upstreamBandwidthProfile.equals(that.upstreamBandwidthProfile) :
+                that.upstreamBandwidthProfile != null) {
+            return false;
+        }
+        if (downstreamBandwidthProfile != null ? !downstreamBandwidthProfile.equals(that.downstreamBandwidthProfile) :
+                that.downstreamBandwidthProfile != null) {
+            return false;
+        }
+        return serviceName != null ? serviceName.equals(that.serviceName) : that.serviceName == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = uniTagMatch != null ? uniTagMatch.hashCode() : 0;
+        result = 31 * result + (ponCTag != null ? ponCTag.hashCode() : 0);
+        result = 31 * result + (ponSTag != null ? ponSTag.hashCode() : 0);
+        result = 31 * result + usPonCTagPriority;
+        result = 31 * result + usPonSTagPriority;
+        result = 31 * result + dsPonCTagPriority;
+        result = 31 * result + dsPonSTagPriority;
+        result = 31 * result + technologyProfileId;
+        result = 31 * result + (upstreamBandwidthProfile != null ? upstreamBandwidthProfile.hashCode() : 0);
+        result = 31 * result + (downstreamBandwidthProfile != null ? downstreamBandwidthProfile.hashCode() : 0);
+        result = 31 * result + (serviceName != null ? serviceName.hashCode() : 0);
+        result = 31 * result + (enableMacLearning ? 1 : 0);
+        result = 31 * result + (configuredMacAddress != null ? configuredMacAddress.hashCode() : 0);
+        result = 31 * result + (isDhcpRequired ? 1 : 0);
+        result = 31 * result + (isIgmpRequired ? 1 : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("UniTagInformation{");
+        sb.append("uniTagMatch=").append(uniTagMatch);
+        sb.append(", ponCTag=").append(ponCTag);
+        sb.append(", ponSTag=").append(ponSTag);
+        sb.append(", usPonCTagPriority=").append(usPonCTagPriority);
+        sb.append(", usPonSTagPriority=").append(usPonSTagPriority);
+        sb.append(", dsPonCTagPriority=").append(dsPonCTagPriority);
+        sb.append(", dsPonSTagPriority=").append(dsPonSTagPriority);
+        sb.append(", technologyProfileId=").append(technologyProfileId);
+        sb.append(", enableMacLearning=").append(enableMacLearning);
+        sb.append(", upstreamBandwidthProfile='").append(upstreamBandwidthProfile).append('\'');
+        sb.append(", downstreamBandwidthProfile='").append(downstreamBandwidthProfile).append('\'');
+        sb.append(", serviceName='").append(serviceName).append('\'');
+        sb.append(", configuredMacAddress='").append(configuredMacAddress).append('\'');
+        sb.append(", isDhcpRequired=").append(isDhcpRequired);
+        sb.append(", isIgmpRequired=").append(isIgmpRequired);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public static final class Builder {
+
+        private VlanId uniTagMatch;
+        private VlanId ponCTag;
+        private VlanId ponSTag;
+        private int usPonCTagPriority;
+        private int usPonSTagPriority;
+        private int dsPonCTagPriority;
+        private int dsPonSTagPriority;
+        private int technologyProfileId;
+        private String upstreamBandwidthProfile;
+        private String downstreamBandwidthProfile;
+        private String serviceName;
+        private boolean enableMacLearning;
+        private String configuredMacAddress;
+        private boolean isDhcpRequired;
+        private boolean isIgmpRequired;
+
+        public final Builder setUniTagMatch(final VlanId uniTagMatch) {
+            this.uniTagMatch = uniTagMatch;
+            return this;
+        }
+
+        public final Builder setPonCTag(final VlanId ponCTag) {
+            this.ponCTag = ponCTag;
+            return this;
+        }
+
+        public final Builder setPonSTag(final VlanId ponSTag) {
+            this.ponSTag = ponSTag;
+            return this;
+        }
+
+        public final Builder setUsPonCTagPriority(final int usPonCTagPriority) {
+            this.usPonCTagPriority = usPonCTagPriority;
+            return this;
+        }
+
+        public final Builder setUsPonSTagPriority(final int usPonSTagPriority) {
+            this.usPonSTagPriority = usPonSTagPriority;
+            return this;
+        }
+
+        public final Builder setDsPonCTagPriority(final int dsPonCTagPriority) {
+            this.dsPonCTagPriority = dsPonCTagPriority;
+            return this;
+        }
+
+        public final Builder setDsPonSTagPriority(final int dsPonSTagPriority) {
+            this.dsPonSTagPriority = dsPonSTagPriority;
+            return this;
+        }
+
+        public final Builder setTechnologyProfileId(final int technologyProfileId) {
+            this.technologyProfileId = technologyProfileId;
+            return this;
+        }
+
+        public final Builder setUpstreamBandwidthProfile(final String upstreamBandwidthProfile) {
+            this.upstreamBandwidthProfile = upstreamBandwidthProfile;
+            return this;
+        }
+
+        public final Builder setDownstreamBandwidthProfile(final String downstreamBandwidthProfile) {
+            this.downstreamBandwidthProfile = downstreamBandwidthProfile;
+            return this;
+        }
+
+        public final Builder setServiceName(final String serviceName) {
+            this.serviceName = serviceName;
+            return this;
+        }
+
+        public final Builder setEnableMacLearning(final boolean enableMacLearning) {
+            this.enableMacLearning = enableMacLearning;
+            return this;
+        }
+
+        public final Builder setConfiguredMacAddress(final String configuredMacAddress) {
+            this.configuredMacAddress = configuredMacAddress;
+            return this;
+        }
+
+        public final Builder setIsDhcpRequired(final boolean isDhcpRequired) {
+            this.isDhcpRequired = isDhcpRequired;
+            return this;
+        }
+
+        public final Builder setIsIgmpRequired(final boolean isIgmpRequired) {
+            this.isIgmpRequired = isIgmpRequired;
+            return this;
+        }
+
+        public final UniTagInformation build() {
+            return new UniTagInformation(this.uniTagMatch, this.ponCTag,
+                    this.ponSTag, this.usPonCTagPriority, this.usPonSTagPriority,
+                    this.dsPonCTagPriority, this.dsPonSTagPriority, this.technologyProfileId,
+                    this.upstreamBandwidthProfile, this.downstreamBandwidthProfile, this.serviceName,
+                    this.enableMacLearning, this.configuredMacAddress, this.isDhcpRequired, this.isIgmpRequired);
+        }
+    }
+}
diff --git a/app/src/main/java/org/opencord/sadis/impl/SubscriberAndDeviceInformationCodec.java b/app/src/main/java/org/opencord/sadis/impl/SubscriberAndDeviceInformationCodec.java
index e3f2996..4208a5e 100644
--- a/app/src/main/java/org/opencord/sadis/impl/SubscriberAndDeviceInformationCodec.java
+++ b/app/src/main/java/org/opencord/sadis/impl/SubscriberAndDeviceInformationCodec.java
@@ -16,31 +16,91 @@
 package org.opencord.sadis.impl;
 
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Lists;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
 import org.onosproject.codec.CodecContext;
 import org.onosproject.codec.JsonCodec;
 import org.opencord.sadis.SubscriberAndDeviceInformation;
+import org.opencord.sadis.UniTagInformation;
 
-public  class SubscriberAndDeviceInformationCodec extends JsonCodec<SubscriberAndDeviceInformation> {
-      @Override
-      public ObjectNode encode(SubscriberAndDeviceInformation entry, CodecContext context) {
-          return context.mapper().createObjectNode()
-                                    .put("id", entry.id())
-                                    .put("cTag", (entry.cTag() == null) ? "" : entry.cTag().toString())
-                                    .put("sTag", (entry.sTag() == null) ? "" : entry.sTag().toString())
-                                    .put("nasPortId", entry.nasPortId())
-                                    .put("uplinkPort", entry.uplinkPort())
-                                    .put("slot", entry.slot())
-                                    .put("hardwareIdentifier", (entry.hardwareIdentifier() == null) ? "" :
-                                          entry.hardwareIdentifier().toString())
-                                    .put("ipAddress", (entry.ipAddress() == null) ? "" : entry.ipAddress().toString())
-                                    .put("nasId", entry.nasId())
-                                    .put("circuiltId", (entry.circuitId() == null) ? "" : entry.circuitId())
-                                    .put("remoteId", (entry.remoteId() == null) ? "" : entry.remoteId())
-                                    .put("technologyProfileId", entry.technologyProfileId())
-                                    .put("upstreamBandwidthProfile", (entry.upstreamBandwidthProfile() == null) ?
-                                            "" : entry.upstreamBandwidthProfile())
-                                    .put("downstreamBandwidthProfile", (entry.downstreamBandwidthProfile() == null) ?
-                                            "" : entry.downstreamBandwidthProfile());
+import java.util.ArrayList;
+import java.util.List;
 
-      }
+public class SubscriberAndDeviceInformationCodec extends JsonCodec<SubscriberAndDeviceInformation> {
+
+    private static final String ID = "id";
+    private static final String NAS_PORT_ID = "nasPortId";
+    private static final String UPLINK_PORT = "uplinkPort";
+    private static final String SLOT = "slot";
+    private static final String HARDWARE_IDENTIFIER = "hardwareIdentifier";
+    private static final String IP_ADDRESS = "ipAddress";
+    private static final String NAS_ID = "nasId";
+    private static final String CIRCUIT_ID = "circuitId";
+    private static final String REMOTE_ID = "remoteId";
+    private static final String UNI_TAG_LIST = "uniTagList";
+    private static final String EMPTY_STRING = "";
+    private static final int NO_VALUE = -1;
+
+    @Override
+    public ObjectNode encode(SubscriberAndDeviceInformation entry, CodecContext context) {
+
+        List<ObjectNode> uniTagListNodes = Lists.newArrayList();
+        List<UniTagInformation> uniTagList = entry.uniTagList();
+        if (uniTagList != null) {
+            for (UniTagInformation uniTagInformation : uniTagList) {
+                uniTagListNodes.add(context.encode(uniTagInformation, UniTagInformation.class));
+            }
+        }
+        return context.mapper().createObjectNode()
+                .put(ID, entry.id())
+                .put(NAS_PORT_ID, entry.nasPortId())
+                .put(UPLINK_PORT, entry.uplinkPort())
+                .put(SLOT, entry.slot())
+                .put(HARDWARE_IDENTIFIER, (entry.hardwareIdentifier() == null) ? EMPTY_STRING :
+                        entry.hardwareIdentifier().toString())
+                .put(IP_ADDRESS, (entry.ipAddress() == null) ? EMPTY_STRING : entry.ipAddress().toString())
+                .put(NAS_ID, entry.nasId())
+                .put(CIRCUIT_ID, (entry.circuitId() == null) ? EMPTY_STRING : entry.circuitId())
+                .put(REMOTE_ID, (entry.remoteId() == null) ? EMPTY_STRING : entry.remoteId())
+                .put(UNI_TAG_LIST, uniTagListNodes.toString());
+    }
+
+    @Override
+    public SubscriberAndDeviceInformation decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+        if (json.get(ID) == null) {
+            return null;
+        }
+
+        SubscriberAndDeviceInformation info = new SubscriberAndDeviceInformation();
+        info.setId(json.get(ID).asText());
+        info.setNasPortId(json.get(NAS_PORT_ID) == null ? EMPTY_STRING : json.get(NAS_PORT_ID).asText());
+        info.setUplinkPort(json.get(UPLINK_PORT) == null ? NO_VALUE : json.get(UPLINK_PORT).asInt());
+        info.setSlot(json.get(SLOT) == null ? NO_VALUE : json.get(SLOT).asInt());
+        info.setNasId(json.get(NAS_ID) == null ? EMPTY_STRING : json.get(NAS_ID).asText());
+        info.setCircuitId(json.get(CIRCUIT_ID) == null ? EMPTY_STRING : json.get(CIRCUIT_ID).asText());
+        info.setRemoteId(json.get(REMOTE_ID) == null ? EMPTY_STRING : json.get(REMOTE_ID).asText());
+
+        if (json.get(HARDWARE_IDENTIFIER) != null) {
+            info.setHardwareIdentifier(MacAddress.valueOf(json.get(HARDWARE_IDENTIFIER).asText()));
+        }
+
+        if (json.get(IP_ADDRESS) != null) {
+            info.setIPAddress(Ip4Address.valueOf(json.get(IP_ADDRESS).asText()));
+        }
+
+        if (json.get(UNI_TAG_LIST) != null) {
+            List<UniTagInformation> uniTagList = new ArrayList<>();
+            json.get(UNI_TAG_LIST).forEach(entry -> {
+                uniTagList.add(new SubscriberAndDeviceInformationConfig()
+                        .getUniTagInformation(entry));
+
+            });
+            info.setUniTagList(uniTagList);
+        }
+        return info;
+    }
 }
diff --git a/app/src/main/java/org/opencord/sadis/impl/SubscriberAndDeviceInformationConfig.java b/app/src/main/java/org/opencord/sadis/impl/SubscriberAndDeviceInformationConfig.java
index 61e097b..d794433 100644
--- a/app/src/main/java/org/opencord/sadis/impl/SubscriberAndDeviceInformationConfig.java
+++ b/app/src/main/java/org/opencord/sadis/impl/SubscriberAndDeviceInformationConfig.java
@@ -20,10 +20,12 @@
 import java.util.List;
 
 import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 import org.opencord.sadis.BaseConfig;
 import org.opencord.sadis.SubscriberAndDeviceInformation;
 
+import org.opencord.sadis.UniTagInformation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -50,8 +52,6 @@
  *     "entries" : [
  *         {
  *             "id"                         : "uniqueid",
- *             "ctag"                       : int,
- *             "stag"                       : int,
  *             "nasportid"                  : string,
  *             "port"                       : int,
  *             "slot"                       : int,
@@ -59,10 +59,26 @@
  *             "ipAddress"                  : string,
  *             "nasId"                      : string,
  *             "circuitId"                  : string,
- *             "removeId"                   : string,
- *             "technologyProfileId"        : int,
- *             "upstreamBandwidthProfile"   : string,
- *             "downstreamBandwidthProfile" : string
+ *             "remoteId"                   : string,
+ *             "uniTagList": [
+ *                  {
+ *                  "uniTagMatch"               : int,
+ *                  "ponCTag"                   : string,
+ *                  "ponSTag"                   : string,
+ *                  "usPonCTagPriority"         : int,
+ *                  "dsPonCTagPriority"         : int,
+ *                  "usPonSTagPriority"         : int,
+ *                  "dsPonSTagPriority"         : int,
+ *                  "technologyProfileId"       : int,
+ *                  "upstreamBandwidthProfile"  : string,
+ *                  "downstreamBandwidthProfile": string,
+ *                  "enableMacLearning"         : string,
+ *                  "configuredDacAddress"      : string,
+ *                  "isDhcpRequired"            : string,
+ *                  "isIgmpRequired"            : string,
+ *                  "serviceName"               : string
+ *                 }
+ *                 ]
  *         }, ...
  *     ]
  * }
@@ -71,6 +87,23 @@
 public class SubscriberAndDeviceInformationConfig extends BaseConfig<SubscriberAndDeviceInformation> {
 
     private final Logger log = LoggerFactory.getLogger(this.getClass());
+    private static final int NO_PCP = -1;
+    private static final String NO_SN = "";
+    private static final String UNI_TAG_MATCH = "uniTagMatch";
+    private static final String PON_C_TAG = "ponCTag";
+    private static final String PON_S_TAG = "ponSTag";
+    private static final String US_C_TAG_PCP = "usPonCTagPriority";
+    private static final String US_S_TAG_PCP = "usPonSTagPriority";
+    private static final String DS_C_TAG_PCP = "dsPonCTagPriority";
+    private static final String DS_S_TAG_PCP = "dsPonSTagPriority";
+    private static final String MAC_LEARNING = "enableMacLearning";
+    private static final String TP_ID = "technologyProfileId";
+    private static final String US_BW = "upstreamBandwidthProfile";
+    private static final String DS_BW = "downstreamBandwidthProfile";
+    private static final String SERVICE_NAME = "serviceName";
+    private static final String IS_DHCP_REQ = "isDhcpRequired";
+    private static final String IS_IGMP_REQ = "isIgmpRequired";
+    private static final String MAC_ADDRESS = "configuredMacAddress";
 
     public List<SubscriberAndDeviceInformation> getEntries() {
         List<SubscriberAndDeviceInformation> result = new ArrayList<>();
@@ -78,6 +111,7 @@
         SimpleModule module = new SimpleModule();
         module.addDeserializer(VlanId.class, new VlanIdDeserializer());
         module.addDeserializer(Ip4Address.class, new Ip4AddressDeserializer());
+        module.addDeserializer(UniTagInformation.class, new UniTagDeserializer());
         mapper.registerModule(module);
         final JsonNode entries = this.object.path(ENTRIES);
         entries.forEach(entry -> {
@@ -110,4 +144,44 @@
             return Ip4Address.valueOf(node.asText());
         }
     }
+
+    public class UniTagDeserializer extends JsonDeserializer<UniTagInformation> {
+        @Override
+        public UniTagInformation deserialize(JsonParser jp, DeserializationContext ctxt)
+                throws IOException {
+            ObjectCodec oc = jp.getCodec();
+            JsonNode node = oc.readTree(jp);
+            return getUniTagInformation(node);
+        }
+    }
+
+    public UniTagInformation getUniTagInformation(JsonNode node) {
+        return new UniTagInformation.Builder()
+                .setUniTagMatch(VlanId.vlanId(node.get(UNI_TAG_MATCH) == null ? VlanId.NO_VID
+                        : (short) node.get(UNI_TAG_MATCH).asInt()))
+                .setPonCTag(VlanId.vlanId((short) node.get(PON_C_TAG).asInt()))
+                .setPonSTag(VlanId.vlanId((short) node.get(PON_S_TAG).asInt()))
+                .setUsPonCTagPriority(node.get(US_C_TAG_PCP) == null ? NO_PCP :
+                        node.get(US_C_TAG_PCP).asInt())
+                .setUsPonSTagPriority(node.get(US_S_TAG_PCP) == null ? NO_PCP :
+                        node.get(US_S_TAG_PCP).asInt())
+                .setDsPonCTagPriority(node.get(DS_C_TAG_PCP) == null ? NO_PCP :
+                        node.get(DS_C_TAG_PCP).asInt())
+                .setDsPonSTagPriority(node.get(DS_S_TAG_PCP) == null ? NO_PCP :
+                        node.get(DS_S_TAG_PCP).asInt())
+                .setEnableMacLearning(node.get(MAC_LEARNING) == null ? false :
+                        node.get(MAC_LEARNING).asBoolean())
+                .setTechnologyProfileId(node.get(TP_ID).asInt())
+                .setUpstreamBandwidthProfile(node.get(US_BW) == null ? null
+                        : node.get(US_BW).asText())
+                .setDownstreamBandwidthProfile(node.get(DS_BW) == null ? null
+                        : node.get(DS_BW).asText())
+                .setServiceName(node.get(SERVICE_NAME) == null ? NO_SN :
+                        node.get(SERVICE_NAME).asText())
+                .setIsDhcpRequired(node.get(IS_DHCP_REQ) == null ? false : node.get(IS_DHCP_REQ).asBoolean())
+                .setIsIgmpRequired(node.get(IS_IGMP_REQ) == null ? false : node.get(IS_IGMP_REQ).asBoolean())
+                .setConfiguredMacAddress(node.get(MAC_ADDRESS) == null ? MacAddress.NONE.toString() :
+                        node.get(MAC_ADDRESS).asText())
+                .build();
+    }
 }
diff --git a/app/src/main/java/org/opencord/sadis/impl/UniTagInformationCodec.java b/app/src/main/java/org/opencord/sadis/impl/UniTagInformationCodec.java
new file mode 100644
index 0000000..5e27e52
--- /dev/null
+++ b/app/src/main/java/org/opencord/sadis/impl/UniTagInformationCodec.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2017-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.sadis.impl;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.VlanId;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.opencord.sadis.UniTagInformation;
+
+public class UniTagInformationCodec extends JsonCodec<UniTagInformation> {
+
+    private static final String UNI_TAG_MATCH = "uniTagMatch";
+    private static final String PON_CTAG = "ponCTag";
+    private static final String PON_STAG = "ponSTag";
+    private static final String US_PON_CTAG_PCP = "usPonCTagPriority";
+    private static final String US_PON_STAG_PCP = "usPonSTagPriority";
+    private static final String DS_PON_CTAG_PCP = "dsPonCTagPriority";
+    private static final String DS_PON_STAG_PCP = "dsPonSTagPriority";
+    private static final String TP_ID = "technologyProfileId";
+    private static final String US_BP = "upstreamBandwidthProfile";
+    private static final String DS_BP = "downstreamBandwidthProfile";
+    private static final String SN = "serviceName";
+    private static final String MAC_LEARN = "enableMacLearning";
+    private static final String MAC = "configuredMacAddress";
+    private static final String DHCP_REQ = "isDhcpRequired";
+    private static final String IGMP_REQ = "isIgmpRequired";
+    private static final int NO_PCP = -1;
+    private static final int NO_TP = -1;
+    private static final String EMPTY_BP = "";
+    private static final String EMPTY_SN = "";
+    private static final boolean DEFAULT_MAC_LEARN = false;
+    private static final String EMPTY_MAC = "";
+    private static final boolean DEFAULT_DHCP_REQ = false;
+    private static final boolean DEFAULT_IGMP_REQ = false;
+
+    @Override
+    public ObjectNode encode(UniTagInformation entry, CodecContext context) {
+        return context.mapper().createObjectNode()
+                .put(UNI_TAG_MATCH, entry.getUniTagMatch().toShort())
+                .put(PON_CTAG, entry.getPonCTag().toShort())
+                .put(PON_STAG, entry.getPonSTag().toShort())
+                .put(US_PON_CTAG_PCP, entry.getUsPonCTagPriority())
+                .put(US_PON_STAG_PCP, entry.getUsPonSTagPriority())
+                .put(DS_PON_CTAG_PCP, entry.getDsPonCTagPriority())
+                .put(DS_PON_STAG_PCP, entry.getDsPonSTagPriority())
+                .put(TP_ID, entry.getTechnologyProfileId())
+                .put(US_BP, entry.getUpstreamBandwidthProfile())
+                .put(DS_BP, entry.getDownstreamBandwidthProfile())
+                .put(SN, entry.getServiceName())
+                .put(MAC_LEARN, entry.getEnableMacLearning())
+                .put(MAC, entry.getConfiguredMacAddress())
+                .put(DHCP_REQ, entry.getIsDhcpRequired())
+                .put(IGMP_REQ, entry.getIsIgmpRequired());
+    }
+
+    @Override
+    public UniTagInformation decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        UniTagInformation.Builder tagInfoBuilder = new UniTagInformation.Builder();
+        tagInfoBuilder.setUniTagMatch(json.get(UNI_TAG_MATCH) == null ? VlanId.vlanId(VlanId.NO_VID) :
+                VlanId.vlanId(json.get(UNI_TAG_MATCH).shortValue()))
+                .setPonCTag(json.get(PON_CTAG) == null ? VlanId.vlanId(VlanId.NO_VID) :
+                        VlanId.vlanId(json.get(PON_CTAG).shortValue()))
+                .setPonCTag(json.get(PON_STAG) == null ? VlanId.vlanId(VlanId.NO_VID) :
+                        VlanId.vlanId(json.get(PON_STAG).shortValue()))
+                .setUsPonCTagPriority(json.get(US_PON_CTAG_PCP) == null ? NO_PCP :
+                        json.get(US_PON_CTAG_PCP).asInt())
+                .setUsPonSTagPriority(json.get(US_PON_STAG_PCP) == null ? NO_PCP :
+                        json.get(US_PON_STAG_PCP).asInt())
+                .setDsPonCTagPriority(json.get(DS_PON_CTAG_PCP) == null ? NO_PCP :
+                        json.get(DS_PON_CTAG_PCP).asInt())
+                .setDsPonSTagPriority(json.get(DS_PON_STAG_PCP) == null ? NO_PCP :
+                        json.get(DS_PON_STAG_PCP).asInt())
+                .setTechnologyProfileId(json.get(TP_ID) == null ? NO_TP :
+                        json.get(TP_ID).asInt())
+                .setUpstreamBandwidthProfile(json.get(US_BP) == null ? EMPTY_BP :
+                        json.get(US_BP).asText())
+                .setDownstreamBandwidthProfile(json.get(DS_BP) == null ? EMPTY_BP :
+                        json.get(DS_BP).asText())
+                .setServiceName(json.get(SN) == null ? EMPTY_SN :
+                        json.get(SN).asText())
+                .setEnableMacLearning(json.get(MAC_LEARN) == null ? DEFAULT_MAC_LEARN :
+                        json.get(MAC_LEARN).asBoolean())
+                .setConfiguredMacAddress(json.get(MAC) == null ? EMPTY_MAC :
+                        json.get(MAC).asText())
+                .setIsDhcpRequired(json.get(DHCP_REQ) == null ? DEFAULT_DHCP_REQ :
+                        json.get(DHCP_REQ).asBoolean())
+                .setIsIgmpRequired(json.get(IGMP_REQ) == null ? DEFAULT_IGMP_REQ :
+                        json.get(IGMP_REQ).asBoolean());
+
+        return tagInfoBuilder.build();
+    }
+}
diff --git a/app/src/main/java/org/opencord/sadis/rest/SadisWebResource.java b/app/src/main/java/org/opencord/sadis/rest/SadisWebResource.java
index 160874a..b2bfad2 100644
--- a/app/src/main/java/org/opencord/sadis/rest/SadisWebResource.java
+++ b/app/src/main/java/org/opencord/sadis/rest/SadisWebResource.java
@@ -24,16 +24,11 @@
 import org.opencord.sadis.SubscriberAndDeviceInformation;
 import org.onlab.util.ItemNotFoundException;
 
-import java.net.URI;
-import java.net.URISyntaxException;
-
 import javax.ws.rs.GET;
-import javax.ws.rs.POST;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
-import javax.ws.rs.Consumes;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
@@ -46,11 +41,6 @@
     private final ArrayNode node = root.putArray("entry");
     private static final String SUBSCRIBER_NOT_FOUND = "Subscriber not found";
     private static final String BP_NOT_FOUND = "Bandwidth Profile not found";
-    private final SadisService sadisService = get(SadisService.class);
-    private final BaseInformationService<SubscriberAndDeviceInformation> subService =
-            sadisService.getSubscriberInfoService();
-    private final BaseInformationService<BandwidthProfileInformation> bpService =
-            sadisService.getBandwidthProfileService();
 
     /**
      * Get subscriber object.
@@ -64,6 +54,9 @@
     @Path("/subscriber/{id}")
     @Produces(MediaType.APPLICATION_JSON)
     public Response getSubscriber(@PathParam("id") String id) {
+        SadisService sadisService = get(SadisService.class);
+        BaseInformationService<SubscriberAndDeviceInformation> subService =
+                sadisService.getSubscriberInfoService();
         final SubscriberAndDeviceInformation entry = subService.get(id);
         if (entry == null) {
            throw new ItemNotFoundException(SUBSCRIBER_NOT_FOUND);
@@ -84,6 +77,9 @@
      @Path("/cache/subscriber/{id}")
      @Produces(MediaType.APPLICATION_JSON)
      public Response getSubscriberCache(@PathParam("id") String id) {
+         SadisService sadisService = get(SadisService.class);
+         BaseInformationService<SubscriberAndDeviceInformation> subService =
+                 sadisService.getSubscriberInfoService();
          final SubscriberAndDeviceInformation entry = subService.getfromCache(id);
          if (entry == null) {
             throw new ItemNotFoundException(SUBSCRIBER_NOT_FOUND);
@@ -93,22 +89,6 @@
      }
 
     /**
-     * Create subscriber object.
-     *
-     * @return 201 Created
-     */
-    @POST
-    @Path("/subscriber")
-    @Consumes(MediaType.APPLICATION_JSON)
-    public Response postSubscriber() {
-        try {
-            return Response.created(new URI("/subsciber/123")).build();
-        } catch (URISyntaxException e) {
-            return Response.serverError().build();
-        }
-    }
-
-    /**
      * Delete subscriber object.
      *
      * @param id
@@ -118,6 +98,9 @@
     @DELETE
     @Path("/cache/subscriber/{id}")
     public Response deleteSubscriber(@PathParam("id") String id) {
+        SadisService sadisService = get(SadisService.class);
+        BaseInformationService<SubscriberAndDeviceInformation> subService =
+                sadisService.getSubscriberInfoService();
         subService.invalidateId(id);
         return Response.noContent().build();
     }
@@ -130,6 +113,9 @@
     @DELETE
     @Path("/cache/subscriber/")
     public Response deleteAllSubscribers() {
+        SadisService sadisService = get(SadisService.class);
+        BaseInformationService<SubscriberAndDeviceInformation> subService =
+                sadisService.getSubscriberInfoService();
         subService.invalidateAll();
         return Response.noContent().build();
     }
@@ -138,6 +124,9 @@
     @Path("/bandwidthprofile/{id}")
     @Produces(MediaType.APPLICATION_JSON)
     public Response getBandwidthProfile(@PathParam("id") String id) {
+        SadisService sadisService = get(SadisService.class);
+        BaseInformationService<BandwidthProfileInformation> bpService =
+                sadisService.getBandwidthProfileService();
         final BandwidthProfileInformation entry = bpService.get(id);
         if (entry == null) {
             throw new ItemNotFoundException(BP_NOT_FOUND);
@@ -150,6 +139,9 @@
     @Path("/cache/bandwidthprofile/{id}")
     @Produces(MediaType.APPLICATION_JSON)
     public Response getBandwidthProfileCache(@PathParam("id") String id) {
+        SadisService sadisService = get(SadisService.class);
+        BaseInformationService<BandwidthProfileInformation> bpService =
+                sadisService.getBandwidthProfileService();
         final BandwidthProfileInformation entry = bpService.getfromCache(id);
         if (entry == null) {
             throw new ItemNotFoundException(BP_NOT_FOUND);
@@ -161,13 +153,19 @@
     @DELETE
     @Path("/cache/bandwidthprofile/{id}")
     public Response deleteBandwidthProfile(@PathParam("id") String id) {
-        bpService.invalidateAll();
+        SadisService sadisService = get(SadisService.class);
+        BaseInformationService<BandwidthProfileInformation> bpService =
+                sadisService.getBandwidthProfileService();
+        bpService.invalidateId(id);
         return Response.noContent().build();
     }
 
     @DELETE
     @Path("/cache/bandwidthprofile/")
     public Response deleteAllBandwidthProfiles() {
+        SadisService sadisService = get(SadisService.class);
+        BaseInformationService<BandwidthProfileInformation> bpService =
+                sadisService.getBandwidthProfileService();
         bpService.invalidateAll();
         return Response.noContent().build();
     }
diff --git a/app/src/test/java/org/opencord/sadis/impl/BaseSadis.java b/app/src/test/java/org/opencord/sadis/impl/BaseSadis.java
index 7d2604a..7979223 100644
--- a/app/src/test/java/org/opencord/sadis/impl/BaseSadis.java
+++ b/app/src/test/java/org/opencord/sadis/impl/BaseSadis.java
@@ -17,6 +17,10 @@
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Lists;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
 import org.onosproject.codec.impl.CodecManager;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreServiceAdapter;
@@ -26,8 +30,10 @@
 import org.onosproject.net.config.Config;
 import org.onosproject.net.config.NetworkConfigEvent;
 import org.opencord.sadis.BaseConfig;
-import org.opencord.sadis.BaseInformationService;
 import org.opencord.sadis.BaseInformation;
+import org.opencord.sadis.BaseInformationService;
+import org.opencord.sadis.SubscriberAndDeviceInformation;
+import org.opencord.sadis.UniTagInformation;
 
 import java.io.InputStream;
 import java.time.Duration;
@@ -48,6 +54,115 @@
     protected NetworkConfigEvent event;
     protected static NetworkConfigListener configListener;
 
+    private static final short UNI_TAG_MATCH_1 = 100;
+    private static final short UNI_TAG_MATCH_2 = 200;
+    private static final short C_TAG_1 = 2;
+    private static final short S_TAG_1 = 2;
+    private static final short S_TAG_2 = 3;
+    private static final int C_TAG_PRIORITY = 0;
+    private static final int S_TAG_PRIORITY = 1;
+    private static final int TECH_PROF_ID_1 = 64;
+    private static final int TECH_PROF_ID_2 = 65;
+
+    private static final String HSA = "HSA";
+    private static final String IPTV = "IPTV";
+    private static final String NAS_PORT_ID = "1/1/2";
+
+    private static final short PORT_1 = 125;
+    private static final short PORT_2 = 129;
+    private static final short PORT_3 = 130;
+    private static final short PORT_4 = 132;
+
+    private static final short SLOT_1 = 3;
+    private static final short SLOT_2 = 4;
+    private static final short SLOT_3 = 7;
+    private static final short SLOT_4 = 1;
+
+    private static final String MAC1 = "aa:bb:cc:dd:ee:ff";
+    private static final String MAC2 = "ff:aa:dd:cc:bb:ee";
+    private static final String MAC3 = "ff:cc:dd:aa:ee:bb";
+
+    private static final String NAS1 = "XXX-NASID";
+    private static final String NAS2 = "YYY-NASID";
+    private static final String NAS3 = "MNO-NASID";
+    private static final String NAS4 = "PQR-NASID";
+
+    private static final String CIRCUIT1 = "circuit123";
+    private static final String CIRCUIT2 = "circuit234";
+    private static final String CIRCUIT3 = "circuit567";
+    private static final String CIRCUIT4 = "circuit678";
+
+    private static final String REMOTE1 = "remote123";
+    private static final String REMOTE2 = "remote234";
+    private static final String REMOTE3 = "remote567";
+    private static final String REMOTE4 = "remote678";
+
+    private static final String IP1 = "10.10.10.10";
+    private static final String IP2 = "1.1.1.1";
+    private static final String IP3 = "30.30.30.30";
+    private static final String IP4 = "15.15.15.15";
+
+    protected static final String ID1 = "1";
+    protected static final String ID2 = "2";
+    protected static final String ID3 = "3";
+    protected static final String ID4 = "4";
+    protected static final String ID5 = "5";
+
+    UniTagInformation ttService1 = new UniTagInformation.Builder()
+            .setUniTagMatch(VlanId.vlanId(UNI_TAG_MATCH_1))
+            .setPonCTag(VlanId.vlanId(C_TAG_1))
+            .setPonSTag(VlanId.vlanId(S_TAG_1))
+            .setUsPonCTagPriority(C_TAG_PRIORITY)
+            .setUsPonSTagPriority(S_TAG_PRIORITY)
+            .setDsPonCTagPriority(C_TAG_PRIORITY)
+            .setDsPonSTagPriority(S_TAG_PRIORITY)
+            .setTechnologyProfileId(TECH_PROF_ID_1)
+            .setUpstreamBandwidthProfile(HSA)
+            .setDownstreamBandwidthProfile(HSA)
+            .setServiceName(HSA)
+            .build();
+
+    UniTagInformation ttService2 = new UniTagInformation.Builder()
+            .setUniTagMatch(VlanId.vlanId(UNI_TAG_MATCH_2))
+            .setPonCTag(VlanId.vlanId(C_TAG_1))
+            .setPonSTag(VlanId.vlanId(S_TAG_2))
+            .setUsPonCTagPriority(C_TAG_PRIORITY)
+            .setUsPonSTagPriority(S_TAG_PRIORITY)
+            .setDsPonCTagPriority(C_TAG_PRIORITY)
+            .setDsPonSTagPriority((S_TAG_PRIORITY))
+            .setTechnologyProfileId(TECH_PROF_ID_2)
+            .setUpstreamBandwidthProfile(IPTV)
+            .setDownstreamBandwidthProfile(IPTV)
+            .setServiceName(IPTV)
+            .setIsIgmpRequired(true)
+            .setIsDhcpRequired(true)
+            .setEnableMacLearning(true)
+            .setConfiguredMacAddress(MAC2)
+            .build();
+
+    UniTagInformation attService1 = new UniTagInformation.Builder()
+            .setPonCTag(VlanId.vlanId(C_TAG_1))
+            .setPonSTag(VlanId.vlanId(S_TAG_2))
+            .setTechnologyProfileId(TECH_PROF_ID_1)
+            .setUpstreamBandwidthProfile(HSA)
+            .setDownstreamBandwidthProfile(HSA)
+            .build();
+
+    List<UniTagInformation> uniTagListForTT = Lists.newArrayList(ttService1);
+    List<UniTagInformation> uniTagList2ForTT = Lists.newArrayList(ttService1, ttService2);
+    List<UniTagInformation> uniTagList3Att = Lists.newArrayList(attService1);
+
+    SubscriberAndDeviceInformationBuilder entry1 = SubscriberAndDeviceInformationBuilder.build(ID1, NAS_PORT_ID,
+            PORT_1, SLOT_1, MAC1, NAS1, IP1, CIRCUIT1, REMOTE1, uniTagListForTT);
+    SubscriberAndDeviceInformationBuilder entry2 = SubscriberAndDeviceInformationBuilder.build(ID2, NAS_PORT_ID,
+            PORT_2, SLOT_2, MAC1, NAS2, IP2, CIRCUIT2, REMOTE2, uniTagList2ForTT);
+    SubscriberAndDeviceInformationBuilder entry3 = SubscriberAndDeviceInformationBuilder.build(ID3, NAS_PORT_ID,
+            PORT_3, SLOT_3, MAC2, NAS3, IP3, CIRCUIT3, REMOTE3, uniTagListForTT);
+    SubscriberAndDeviceInformationBuilder entry4 = SubscriberAndDeviceInformationBuilder.build(ID4, NAS_PORT_ID,
+            PORT_4, SLOT_4, MAC3, NAS4, IP4, CIRCUIT4, REMOTE4, uniTagList2ForTT);
+    SubscriberAndDeviceInformationBuilder entry5 = SubscriberAndDeviceInformationBuilder.build(ID5, NAS_PORT_ID,
+            PORT_3, SLOT_3, MAC2, NAS3, IP3, CIRCUIT3, REMOTE3, uniTagList3Att);
+
     public void setUp(String localConfig, Class configClass) throws Exception {
         sadis = new SadisManager();
         sadis.coreService = new MockCoreService();
@@ -104,6 +219,33 @@
         }
     }
 
+    private static final class SubscriberAndDeviceInformationBuilder extends SubscriberAndDeviceInformation {
+
+        public static SubscriberAndDeviceInformationBuilder build(String id, String nasPortId,
+                                                                  short port, short slot, String mac,
+                                                                  String nasId, String ipAddress, String circuitId,
+                                                                  String remoteId,
+                                                                  List<UniTagInformation> uniTagList) {
+
+            SubscriberAndDeviceInformationBuilder info = new SubscriberAndDeviceInformationBuilder();
+            info.setId(id);
+            if (slot != -1) {
+                info.setSlot(slot);
+            }
+            info.setNasPortId(nasPortId);
+            info.setUplinkPort(port);
+            info.setHardwareIdentifier(MacAddress.valueOf(mac));
+            info.setIPAddress(Ip4Address.valueOf(ipAddress));
+            info.setNasId(nasId);
+            info.setCircuitId(circuitId);
+            info.setRemoteId(remoteId);
+
+            info.setUniTagList(uniTagList);
+
+            return info;
+        }
+
+    }
 
     /**
      * Mocks an ONOS configuration delegate to allow JSON based configuration to
diff --git a/app/src/test/java/org/opencord/sadis/impl/SubscriberAndDeviceManagerTest.java b/app/src/test/java/org/opencord/sadis/impl/SubscriberAndDeviceManagerTest.java
index 6ff5cc3..fa68966 100644
--- a/app/src/test/java/org/opencord/sadis/impl/SubscriberAndDeviceManagerTest.java
+++ b/app/src/test/java/org/opencord/sadis/impl/SubscriberAndDeviceManagerTest.java
@@ -24,34 +24,17 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
 
-import org.opencord.sadis.SubscriberAndDeviceInformation;
 import org.opencord.sadis.BaseConfig;
-import org.opencord.sadis.BaseInformationService;
 import org.opencord.sadis.BaseInformation;
+import org.opencord.sadis.BaseInformationService;
+import org.opencord.sadis.SubscriberAndDeviceInformation;
 
 /**
  * Set of tests of the SADIS ONOS application component.
  */
 public class SubscriberAndDeviceManagerTest extends BaseSadis {
 
-    SubscriberAndDeviceInformationBuilder entry1 = SubscriberAndDeviceInformationBuilder.build("1", (short) 2,
-            (short) 2, "1/1/2", (short) 125, (short) 3, "aa:bb:cc:dd:ee:ff", "XXX-NASID", "10.10.10.10",
-            "circuit123", "remote123", 64, "1Gb", "1Gb");
-    SubscriberAndDeviceInformationBuilder entry2 = SubscriberAndDeviceInformationBuilder.build("2", (short) 4,
-            (short) 4, "1/1/2", (short) 129, (short) 4, "aa:bb:cc:dd:ee:ff", "YYY-NASID", "1.1.1.1",
-            "circuit234", "remote234", 64, "10Gb", "10Gb");
-    SubscriberAndDeviceInformationBuilder entry3 = SubscriberAndDeviceInformationBuilder.build("3", (short) 7,
-            (short) 8, "1/1/2", (short) 130, (short) 7, "ff:aa:dd:cc:bb:ee", "MNO-NASID", "30.30.30.30",
-            "circuit567", "remote567", 64, "10Gb", "10Gb");
-    SubscriberAndDeviceInformationBuilder entry4 = SubscriberAndDeviceInformationBuilder.build("4", (short) 2,
-            (short) 1, "1/1/2", (short) 132, (short) 1, "ff:cc:dd:aa:ee:bb", "PQR-NASID", "15.15.15.15",
-            "circuit678", "remote678", 64, "5Gb", "5Gb");
-
-
     @Before
     public void setUp() throws Exception {
         config = new SubscriberAndDeviceInformationConfig();
@@ -74,23 +57,9 @@
     private void checkEntriesForSubscriberAndAccessDevice(BaseConfig config) {
         List<SubscriberAndDeviceInformation> entries = config.getEntries();
         assertEquals(3, entries.size());
-
-        SubscriberAndDeviceInformation sub = SubscriberAndDeviceInformationBuilder.build("1", (short) 2, (short) 2,
-                "1/1/2", (short) 125,
-                (short) 3, "aa:bb:cc:dd:ee:ff", "XXX-NASID", "10.10.10.10", "circuit123", "remote123",
-                64, "1Gb", "1Gb");
-        assertTrue(checkEquality(sub, entries.get(0)));
-
-
-        sub = SubscriberAndDeviceInformationBuilder.build("2", (short) 4, (short) 4, "1/1/2", (short) 129,
-                (short) 4, "aa:bb:cc:dd:ee:ff", "YYY-NASID", "1.1.1.1", "circuit234", "remote234",
-                64, "10Gb", "10Gb");
-        assertTrue(checkEquality(sub, entries.get(1)));
-
-        sub = SubscriberAndDeviceInformationBuilder.build("cc:dd:ee:ff:aa:bb", (short) -1, (short) -1, null,
-                (short) -1, (short) -1, "cc:dd:ee:ff:aa:bb", "CCC-NASID", "12.12.12.12", "circuit345", "remote345",
-                64, "10Gb", "10Gb");
-        assertTrue(checkEquality(sub, entries.get(2)));
+        assertTrue(checkEquality(entry1, entries.get(0)));
+        assertTrue(checkEquality(entry2, entries.get(1)));
+        assertTrue(checkEquality(entry5, entries.get(2)));
     }
 
     @Test
@@ -98,14 +67,15 @@
 
         BaseInformationService<SubscriberAndDeviceInformation> subscriberService = sadis.getSubscriberInfoService();
 
-        checkGetForExisting("1", entry1, subscriberService);
-        checkGetForExisting("2", entry2, subscriberService);
+        checkGetForExisting(ID1, entry1, subscriberService);
+        checkGetForExisting(ID2, entry2, subscriberService);
+        checkGetForExisting(ID5, entry5, subscriberService);
 
-        invalidateId("1", subscriberService);
-        checkFromBoth("1", entry1, subscriberService);
+        invalidateId(ID1, subscriberService);
+        checkFromBoth(ID1, entry1, subscriberService);
 
         invalidateAll(subscriberService);
-        checkFromBoth("2", entry2, subscriberService);
+        checkFromBoth(ID2, entry2, subscriberService);
     }
 
 
@@ -120,14 +90,14 @@
         config.init(subject, "sadis-remote-mode-test", node("/RemoteConfig.json"), mapper, delegate);
         configListener.event(event);
 
-        checkGetForExisting("3", entry3, subscriberService);
-        checkGetForExisting("4", entry4, subscriberService);
+        checkGetForExisting(ID3, entry3, subscriberService);
+        checkGetForExisting(ID4, entry4, subscriberService);
 
-        invalidateId("3", subscriberService);
-        checkFromBoth("3", entry3, subscriberService);
+        invalidateId(ID3, subscriberService);
+        checkFromBoth(ID3, entry3, subscriberService);
 
         invalidateAll(subscriberService);
-        checkFromBoth("4", entry4, subscriberService);
+        checkFromBoth(ID4, entry4, subscriberService);
     }
 
     @Test
@@ -136,60 +106,16 @@
         config.init(subject, "sadis-remote-mode-test", node("/RemoteConfig.json"), mapper, delegate);
         configListener.event(event);
 
-        checkGetForExisting("3", null, service);
-        checkGetForNonExist("1", service);
+        checkGetForExisting(ID3, null, service);
+        checkGetForNonExist(ID1, service);
 
         config.init(subject, "sadis-local-mode-test", node("/LocalSubConfig.json"), mapper, delegate);
         configListener.event(event);
 
-        checkGetForExisting("1", null, service);
-        checkGetForNonExist("3", service);
+        checkGetForExisting(ID1, null, service);
+        checkGetForNonExist(ID3, service);
     }
 
-
-    private static final class SubscriberAndDeviceInformationBuilder extends SubscriberAndDeviceInformation {
-
-        public static SubscriberAndDeviceInformationBuilder build(String id, short cTag, short sTag, String nasPortId,
-                                                                  short port, short slot, String mac, String nasId,
-                                                                  String ipAddress, String circuitId, String remoteId,
-                                                                  int technologyProfileId,
-                                                                  String upstreamBandwidthProfile,
-                                                                  String downstreamBandwidthProfile) {
-
-            SubscriberAndDeviceInformationBuilder info = new SubscriberAndDeviceInformationBuilder();
-            info.setId(id);
-            if (cTag != -1) {
-                info.setCTag(VlanId.vlanId(cTag));
-            }
-            if (sTag != -1) {
-                info.setSTag(VlanId.vlanId(sTag));
-            }
-            info.setNasPortId(nasPortId);
-            if (port != -1) {
-                info.setUplinkPort(port);
-            }
-            if (slot != -1) {
-                info.setSlot(slot);
-            }
-            info.setHardwareIdentifier(MacAddress.valueOf(mac));
-            info.setIPAddress(Ip4Address.valueOf(ipAddress));
-            info.setNasId(nasId);
-            info.setCircuitId(circuitId);
-            info.setRemoteId(remoteId);
-
-            if (technologyProfileId != -1) {
-                info.setTechnologyProfileId(technologyProfileId);
-            }
-
-            info.setUpstreamBandwidthProfile(upstreamBandwidthProfile);
-            info.setDownstreamBandwidthProfile(downstreamBandwidthProfile);
-
-            return info;
-        }
-
-    }
-
-    @Override
     public boolean checkEquality(BaseInformation localEntry, BaseInformation entry) {
         SubscriberAndDeviceInformation sub = (SubscriberAndDeviceInformation) localEntry;
         SubscriberAndDeviceInformation other = (SubscriberAndDeviceInformation) localEntry;
@@ -197,13 +123,6 @@
         if (other == null) {
             return false;
         }
-        if (sub.cTag() == null) {
-            if (other.cTag() != null) {
-                return false;
-            }
-        } else if (!sub.cTag().equals(other.cTag())) {
-            return false;
-        }
         if (sub.hardwareIdentifier() == null) {
             if (other.hardwareIdentifier() != null) {
                 return false;
@@ -242,13 +161,6 @@
         if (sub.uplinkPort() != other.uplinkPort()) {
             return false;
         }
-        if (sub.sTag() == null) {
-            if (other.sTag() != null) {
-                return false;
-            }
-        } else if (!sub.sTag().equals(other.sTag())) {
-            return false;
-        }
         if (sub.slot() != other.slot()) {
             return false;
         }
@@ -266,25 +178,13 @@
         } else if (!sub.remoteId().equals(other.remoteId())) {
             return false;
         }
-        if (sub.technologyProfileId() != other.technologyProfileId()) {
-            return false;
-        }
-        if (sub.upstreamBandwidthProfile() == null) {
-            if (other.upstreamBandwidthProfile() != null) {
+        if (sub.uniTagList() == null) {
+            if (other.uniTagList() != null) {
                 return false;
             }
-        } else if (!sub.upstreamBandwidthProfile().equals(other.upstreamBandwidthProfile())) {
-            return false;
-        }
-        if (sub.downstreamBandwidthProfile() == null) {
-            if (other.downstreamBandwidthProfile() != null) {
-                return false;
-            }
-        } else if (!sub.downstreamBandwidthProfile().equals(other.downstreamBandwidthProfile())) {
+        } else if (!sub.uniTagList().equals(other.uniTagList())) {
             return false;
         }
         return true;
     }
-
-
 }
diff --git a/app/src/test/resources/3 b/app/src/test/resources/3
index 496bf28..418b0b0 100644
--- a/app/src/test/resources/3
+++ b/app/src/test/resources/3
@@ -1,7 +1,5 @@
 {
       "id": "3",
-      "cTag": 7,
-      "sTag": 8,
       "nasPortId": "1/1/2",
       "uplinkPort": 130,
       "slot": 7,
@@ -10,7 +8,19 @@
       "nasId":"MNO-NASID",
       "circuitId":"circuit567",
       "remoteId":"remote567",
-      "technologyProfileId":64,
-      "upstreamBandwidthProfile":"10Gb",
-      "downstreamBandwidthProfile":"10Gb"
+      "uniTagList": [
+     	{
+     	    "uniTagMatch":100,
+     		"ponCTag":2,
+     		"ponSTag":2,
+     		"usPonCTagPriority":0,
+     		"usPonSTagPriority":1,
+     		"dsPonCTagPriority": 0,
+     		"dsPonSTagPriority": 0,
+     		"technologyProfileId":64,
+     		"upstreamBandwidthProfile":"HSA",
+     		"downstreamBandwidthProfile":"HSA",
+     		"serviceName":"HSIA"
+     	}
+     ]
 }
diff --git a/app/src/test/resources/4 b/app/src/test/resources/4
index 757e741..ea0b618 100644
--- a/app/src/test/resources/4
+++ b/app/src/test/resources/4
@@ -1,7 +1,5 @@
 {
       "id": "4",
-      "cTag": 2,
-      "sTag": 1,
       "nasPortId": "1/1/2",
       "uplinkPort": 132,
       "slot": 1,
@@ -10,7 +8,32 @@
       "nasId":"PQR-NASID",
       "circuitId":"circuit678",
       "remoteId":"remote678",
-      "technologyProfileId":64,
-      "upstreamBandwidthProfile":"5Gb",
-      "downstreamBandwidthProfile":"5Gb"
+      "uniTagList": [
+      	{
+      	    "uniTagMatch":100,
+      		"ponCTag":2,
+      		"ponSTag":2,
+      		"usPonCTagPriority":0,
+      		"usPonSTagPriority":1,
+      		"dsPonCTagPriority":0,
+      		"dsPonSTagPriority":0,
+      		"technologyProfileId":64,
+      		"upstreamBandwidthProfile":"HSA",
+      		"downstreamBandwidthProfile":"HSA",
+      		"serviceName":"HSIA"
+      	},
+      	{
+      		"uniTagMatch":200,
+      		"ponCTag":3,
+      		"ponSTag":2,
+      		"usPonCTagPriority":0,
+      		"usPonSTagPriority":1,
+      		"dsPonCTagPriority":0,
+      		"dsPonSTagPriority":0,
+      		"technologyProfileId":65,
+      		"upstreamBandwidthProfile":"IPTV",
+      		"downstreamBandwidthProfile":"IPTV",
+      		"serviceName":"IPTV"
+      	}
+      ]
 }
diff --git a/app/src/test/resources/LocalSubConfig.json b/app/src/test/resources/LocalSubConfig.json
index 99c861a..1efee37 100644
--- a/app/src/test/resources/LocalSubConfig.json
+++ b/app/src/test/resources/LocalSubConfig.json
@@ -12,8 +12,6 @@
 	[
 		{
 			"id": "1",
-			"cTag": 2,
-			"sTag": 2,
 			"nasPortId": "1/1/2",
 			"uplinkPort": 125,
 			"slot": 3,
@@ -22,15 +20,25 @@
 			"nasId":"XXX-NASID",
 			"circuitId":"circuit123",
 			"remoteId":"remote123",
-			"technologyProfileId":64,
-			"upstreamBandwidthProfile":"1Gb",
-			"downstreamBandwidthProfile":"1Gb"
+			"uniTagList": [
+				{
+					"uniTagMatch":100,
+					"ponCTag":"2,",
+					"ponSTag":"2",
+					"usPonCTagPriority":0,
+					"usPonSTagPriority":1,
+					"dsPonCTagPriority":0,
+					"dsPonSTagPriority":1,
+					"technologyProfileId":64,
+					"upstreamBandwidthProfile":"HSA",
+					"downstreamBandwidthProfile":"HSA",
+					"serviceName":"HSIA"
+				}
+			]
 		},
 
 		{
 			"id": "2",
-			"cTag": 4,
-			"sTag": 4,
 			"nasPortId": "1/1/2",
 			"uplinkPort": 129,
 			"slot": 4,
@@ -39,21 +47,57 @@
 			"nasId":"YYY-NASID",
 			"circuitId":"circuit234",
 			"remoteId":"remote234",
-			"technologyProfileId":64,
-			"upstreamBandwidthProfile":"10Gb",
-			"downstreamBandwidthProfile":"10Gb"
+			"uniTagList": [
+				{
+					"uniTagMatch":100,
+					"ponCTag":"2,",
+					"ponSTag":"2",
+					"usPonCTagPriority":0,
+					"usPonSTagPriority":1,
+					"dsPonCTagPriority":0,
+					"dsPonSTagPriority":1,
+					"technologyProfileId":64,
+					"upstreamBandwidthProfile":"HSA",
+					"downstreamBandwidthProfile":"HSA",
+					"serviceName":"HSIA"
+				},
+				{
+					"uniTagMatch":200,
+					"ponCTag":3,
+					"ponSTag":2,
+					"usPonCTagPriority":0,
+					"usPonSTagPriority":1,
+					"dsPonCTagPriority": 0,
+					"dsPonSTagPriority": 1,
+					"technologyProfileId":65,
+					"upstreamBandwidthProfile":"IPTV",
+					"downstreamBandwidthProfile":"IPTV",
+					"serviceName":"IPTV",
+					"isIgmpRequired": "true",
+					"isDhcpRequired": "true",
+					"configuredMacAddress": "\"ff:aa:dd:cc:bb:ee\""
+				}
+			]
 		},
-
 		{
-			"id": "cc:dd:ee:ff:aa:bb",
-			"hardwareIdentifier": "cc:dd:ee:ff:aa:bb",
-			"ipAddress":"12.12.12.12",
-			"nasId":"CCC-NASID",
-			"circuitId":"circuit345",
-			"remoteId":"remote345",
-			"technologyProfileId":64,
-			"upstreamBandwidthProfile":"10Gb",
-			"downstreamBandwidthProfile":"10Gb"
+			"id": "5",
+			"nasPortId": "1/1/2",
+			"uplinkPort": 125,
+			"slot": 3,
+			"hardwareIdentifier": "aa:bb:cc:dd:ee:ff",
+			"ipAddress":"10.10.10.10",
+			"nasId":"XXX-NASID",
+			"circuitId":"circuit123",
+			"remoteId":"remote123",
+			"uniTagList": [
+				{
+					"ponCTag":"2,",
+					"ponSTag":"2",
+					"technologyProfileId":64,
+					"upstreamBandwidthProfile":"HSA",
+					"downstreamBandwidthProfile":"HSA"
+				}
+			]
 		}
 	]
 }