[ONOS-5750] Improve MappingEntryBuilder to convert LCAF to ext addr

Change-Id: I0353575633bbe1073413b61ad134634716ad75b4
diff --git a/apps/mappingmanagement/api/src/main/java/org/onosproject/mapping/addresses/ExtensionMappingAddressWrapper.java b/apps/mappingmanagement/api/src/main/java/org/onosproject/mapping/addresses/ExtensionMappingAddressWrapper.java
index a3a539a..474af5a 100644
--- a/apps/mappingmanagement/api/src/main/java/org/onosproject/mapping/addresses/ExtensionMappingAddressWrapper.java
+++ b/apps/mappingmanagement/api/src/main/java/org/onosproject/mapping/addresses/ExtensionMappingAddressWrapper.java
@@ -16,7 +16,6 @@
 package org.onosproject.mapping.addresses;
 
 import org.onosproject.net.DeviceId;
-import org.onosproject.net.flow.criteria.ExtensionSelector;
 
 import java.util.Objects;
 
@@ -25,17 +24,18 @@
  */
 public final class ExtensionMappingAddressWrapper implements MappingAddress {
 
-    private final ExtensionSelector extensionSelector;
+    private final ExtensionMappingAddress extensionMappingAddress;
     private final DeviceId deviceId;
 
     /**
      * Default constructor of ExtensionMappingAddressWrapper.
      *
-     * @param extensionSelector extension selector
-     * @param deviceId          device identifier
+     * @param extensionMappingAddress extension mapping address
+     * @param deviceId device identifier
      */
-    public ExtensionMappingAddressWrapper(ExtensionSelector extensionSelector, DeviceId deviceId) {
-        this.extensionSelector = extensionSelector;
+    public ExtensionMappingAddressWrapper(ExtensionMappingAddress extensionMappingAddress,
+                                          DeviceId deviceId) {
+        this.extensionMappingAddress = extensionMappingAddress;
         this.deviceId = deviceId;
     }
 
@@ -45,12 +45,12 @@
     }
 
     /**
-     * Returns the extension selector.
+     * Returns the extension mapping address.
      *
-     * @return extension selector
+     * @return extension mapping address
      */
-    public ExtensionSelector extensionSelector() {
-        return extensionSelector;
+    public ExtensionMappingAddress extensionMappingAddress() {
+        return extensionMappingAddress;
     }
 
     /**
@@ -64,12 +64,12 @@
 
     @Override
     public String toString() {
-        return type().toString() + TYPE_SEPARATOR + deviceId + "/" + extensionSelector;
+        return type().toString() + TYPE_SEPARATOR + extensionMappingAddress;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(type().ordinal(), extensionSelector, deviceId);
+        return Objects.hash(type().ordinal(), extensionMappingAddress);
     }
 
     @Override
@@ -79,7 +79,7 @@
         }
         if (obj instanceof ExtensionMappingAddressWrapper) {
             ExtensionMappingAddressWrapper that = (ExtensionMappingAddressWrapper) obj;
-            return Objects.equals(extensionSelector, that.extensionSelector) &&
+            return Objects.equals(extensionMappingAddress, that.extensionMappingAddress) &&
                     Objects.equals(deviceId, that.deviceId);
         }
         return false;
diff --git a/apps/mappingmanagement/api/src/main/java/org/onosproject/mapping/addresses/MappingAddresses.java b/apps/mappingmanagement/api/src/main/java/org/onosproject/mapping/addresses/MappingAddresses.java
index a47dae0..1a3cafe 100644
--- a/apps/mappingmanagement/api/src/main/java/org/onosproject/mapping/addresses/MappingAddresses.java
+++ b/apps/mappingmanagement/api/src/main/java/org/onosproject/mapping/addresses/MappingAddresses.java
@@ -17,6 +17,7 @@
 
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
+import org.onosproject.net.DeviceId;
 
 /**
  * Factory class for creating various mapping addresses.
@@ -77,4 +78,16 @@
     public static IPMappingAddress ipv6MappingAddress(IpPrefix ip) {
         return new IPMappingAddress(ip, MappingAddress.Type.IPV6);
     }
+
+    /**
+     * Creates an extension mapping address wrapper.
+     *
+     * @param address extension mapping address
+     * @param deviceId device identifier
+     * @return extension mapping address wrapper
+     */
+    public static ExtensionMappingAddressWrapper
+                  extensionMappingAddressWrapper(ExtensionMappingAddress address, DeviceId deviceId) {
+        return new ExtensionMappingAddressWrapper(address, deviceId);
+    }
 }
diff --git a/providers/lisp/mapping/BUCK b/providers/lisp/mapping/BUCK
index 7e4bb9d..ea1cd66 100644
--- a/providers/lisp/mapping/BUCK
+++ b/providers/lisp/mapping/BUCK
@@ -3,6 +3,7 @@
     '//protocols/lisp/api:onos-protocols-lisp-api',
     '//protocols/lisp/msg:onos-protocols-lisp-msg',
     '//apps/mappingmanagement/api:onos-apps-mappingmanagement-api',
+    '//drivers/lisp:onos-drivers-lisp',
 ]
 
 TEST_DEPS = [
diff --git a/providers/lisp/mapping/pom.xml b/providers/lisp/mapping/pom.xml
index dab2d75..a8dfb24 100644
--- a/providers/lisp/mapping/pom.xml
+++ b/providers/lisp/mapping/pom.xml
@@ -53,6 +53,11 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-drivers-lisp</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
             <groupId>org.easymock</groupId>
             <artifactId>easymock</artifactId>
             <scope>test</scope>
diff --git a/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilder.java b/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilder.java
index 90052c28..7d45745 100644
--- a/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilder.java
+++ b/providers/lisp/mapping/src/main/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilder.java
@@ -19,6 +19,15 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
+import org.onosproject.drivers.lisp.extensions.LispGcAddress;
+import org.onosproject.drivers.lisp.extensions.LispNatAddress;
+import org.onosproject.drivers.lisp.extensions.LispSrcDstAddress;
+import org.onosproject.drivers.lisp.extensions.LispAppDataAddress;
+import org.onosproject.drivers.lisp.extensions.LispListAddress;
+import org.onosproject.drivers.lisp.extensions.LispMulticastAddress;
+import org.onosproject.drivers.lisp.extensions.LispNonceAddress;
+import org.onosproject.drivers.lisp.extensions.LispSegmentAddress;
+import org.onosproject.drivers.lisp.extensions.LispTeAddress;
 import org.onosproject.lisp.msg.protocols.LispLocator;
 import org.onosproject.lisp.msg.protocols.LispMapRecord;
 import org.onosproject.lisp.msg.types.LispAfiAddress;
@@ -27,6 +36,17 @@
 import org.onosproject.lisp.msg.types.LispIpv4Address;
 import org.onosproject.lisp.msg.types.LispIpv6Address;
 import org.onosproject.lisp.msg.types.LispMacAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispMulticastLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispNonceLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispNatLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispGeoCoordinateLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispAsLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispSegmentLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispAppDataLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispListLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispSourceDestLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispTeLcafAddress;
 import org.onosproject.mapping.DefaultMapping;
 import org.onosproject.mapping.DefaultMappingEntry;
 import org.onosproject.mapping.DefaultMappingKey;
@@ -40,6 +60,7 @@
 import org.onosproject.mapping.MappingValue;
 import org.onosproject.mapping.actions.MappingAction;
 import org.onosproject.mapping.actions.MappingActions;
+import org.onosproject.mapping.addresses.ExtensionMappingAddress;
 import org.onosproject.mapping.addresses.MappingAddress;
 import org.onosproject.mapping.addresses.MappingAddresses;
 import org.onosproject.net.DeviceId;
@@ -49,9 +70,6 @@
 import java.util.List;
 import java.util.UUID;
 
-import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.IP4;
-import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.IP6;
-
 /**
  * Mapping entry builder class.
  */
@@ -172,17 +190,16 @@
     private MappingAddress buildAddress(LispMapRecord record) {
 
         return record == null ? null :
-                getAddress(record.getEidPrefixAfi(), record.getMaskLength());
+                getAddress(record.getEidPrefixAfi());
     }
 
     /**
      * Converts LispAfiAddress into abstracted mapping address.
      *
      * @param address LispAfiAddress
-     * @param length  mask length
      * @return abstracted mapping address
      */
-    private MappingAddress getAddress(LispAfiAddress address, int length) {
+    private MappingAddress getAddress(LispAfiAddress address) {
 
         if (address == null) {
             log.warn("Address is not specified.");
@@ -191,13 +208,9 @@
 
         switch (address.getAfi()) {
             case IP4:
-                IpAddress ipv4Address = ((LispIpv4Address) address).getAddress();
-                IpPrefix ipv4Prefix = IpPrefix.valueOf(ipv4Address, length);
-                return MappingAddresses.ipv4MappingAddress(ipv4Prefix);
+                return afi2MappingAddress(address);
             case IP6:
-                IpAddress ipv6Address = ((LispIpv6Address) address).getAddress();
-                IpPrefix ipv6Prefix = IpPrefix.valueOf(ipv6Address, length);
-                return MappingAddresses.ipv6MappingAddress(ipv6Prefix);
+                return afi2MappingAddress(address);
             case AS:
                 int asNum = ((LispAsAddress) address).getASNum();
                 return MappingAddresses.asMappingAddress(String.valueOf(asNum));
@@ -209,8 +222,8 @@
                 MacAddress macAddress = ((LispMacAddress) address).getAddress();
                 return MappingAddresses.ethMappingAddress(macAddress);
             case LCAF:
-                // TODO: need to use extension address to abstract LCAF address
-                break;
+                LispLcafAddress lcafAddress = (LispLcafAddress) address;
+                return lcaf2Extension(lcafAddress);
             default:
                 log.warn("Unsupported address type {}", address.getAfi());
                 break;
@@ -220,6 +233,204 @@
     }
 
     /**
+     * Converts LCAF address to extension mapping address.
+     *
+     * @param lcaf LCAF address
+     * @return extension mapping address
+     */
+    private MappingAddress lcaf2Extension(LispLcafAddress lcaf) {
+
+        ExtensionMappingAddress ema;
+
+        switch (lcaf.getType()) {
+            case LIST:
+                LispListLcafAddress lcafListAddress = (LispListLcafAddress) lcaf;
+                MappingAddress ipv4Ma =
+                        afi2MappingAddress(lcafListAddress.getAddresses().get(0));
+                MappingAddress ipv6Ma =
+                        afi2MappingAddress(lcafListAddress.getAddresses().get(1));
+
+                ema = new LispListAddress.Builder()
+                        .withIpv4(ipv4Ma)
+                        .withIpv6(ipv6Ma)
+                        .build();
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case SEGMENT:
+                LispSegmentLcafAddress segmentLcafAddress = (LispSegmentLcafAddress) lcaf;
+
+                ema = new LispSegmentAddress.Builder()
+                        .withInstanceId(segmentLcafAddress.getInstanceId())
+                        .withAddress(getAddress(segmentLcafAddress.getAddress()))
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case AS:
+                LispAsLcafAddress asLcafAddress = (LispAsLcafAddress) lcaf;
+
+                ema = new org.onosproject.drivers.lisp.extensions.LispAsAddress.Builder()
+                        .withAsNumber(asLcafAddress.getAsNumber())
+                        .withAddress(getAddress(asLcafAddress.getAddress()))
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case APPLICATION_DATA:
+
+                LispAppDataLcafAddress appLcafAddress = (LispAppDataLcafAddress) lcaf;
+
+                ema = new LispAppDataAddress.Builder()
+                        .withProtocol(appLcafAddress.getProtocol())
+                        .withIpTos(appLcafAddress.getIpTos())
+                        .withLocalPortLow(appLcafAddress.getLocalPortLow())
+                        .withLocalPortHigh(appLcafAddress.getLocalPortHigh())
+                        .withRemotePortLow(appLcafAddress.getRemotePortLow())
+                        .withRemotePortHigh(appLcafAddress.getRemotePortHigh())
+                        .withAddress(getAddress(appLcafAddress.getAddress()))
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case GEO_COORDINATE:
+
+                LispGeoCoordinateLcafAddress gcLcafAddress = (LispGeoCoordinateLcafAddress) lcaf;
+
+                ema = new LispGcAddress.Builder()
+                        .withIsNorth(gcLcafAddress.isNorth())
+                        .withLatitudeDegree(gcLcafAddress.getLatitudeDegree())
+                        .withLatitudeMinute(gcLcafAddress.getLatitudeMinute())
+                        .withLatitudeSecond(gcLcafAddress.getLatitudeSecond())
+                        .withIsEast(gcLcafAddress.isEast())
+                        .withLongitudeDegree(gcLcafAddress.getLongitudeDegree())
+                        .withLongitudeMinute(gcLcafAddress.getLongitudeMinute())
+                        .withLongitudeSecond(gcLcafAddress.getLongitudeSecond())
+                        .withAltitude(gcLcafAddress.getAltitude())
+                        .withAddress(getAddress(gcLcafAddress.getAddress()))
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case NAT:
+
+                LispNatLcafAddress natLcafAddress = (LispNatLcafAddress) lcaf;
+
+                List<MappingAddress> mas = Lists.newArrayList();
+
+                natLcafAddress.getRtrRlocAddresses().forEach(rtr -> mas.add(getAddress(rtr)));
+
+                ema = new LispNatAddress.Builder()
+                        .withMsUdpPortNumber(natLcafAddress.getMsUdpPortNumber())
+                        .withEtrUdpPortNumber(natLcafAddress.getEtrUdpPortNumber())
+                        .withMsRlocAddress(getAddress(natLcafAddress.getMsRlocAddress()))
+                        .withGlobalEtrRlocAddress(getAddress(natLcafAddress.getGlobalEtrRlocAddress()))
+                        .withPrivateEtrRlocAddress(getAddress(natLcafAddress.getPrivateEtrRlocAddress()))
+                        .withRtrRlocAddresses(mas)
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case NONCE:
+
+                LispNonceLcafAddress nonceLcafAddress = (LispNonceLcafAddress) lcaf;
+
+                ema = new LispNonceAddress.Builder()
+                        .withNonce(nonceLcafAddress.getNonce())
+                        .withAddress(getAddress(nonceLcafAddress.getAddress()))
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case MULTICAST:
+
+                LispMulticastLcafAddress multiLcafAddress = (LispMulticastLcafAddress) lcaf;
+
+                ema = new LispMulticastAddress.Builder()
+                        .withInstanceId(multiLcafAddress.getInstanceId())
+                        .withSrcAddress(getAddress(multiLcafAddress.getSrcAddress()))
+                        .withSrcMaskLength(multiLcafAddress.getSrcMaskLength())
+                        .withGrpAddress(getAddress(multiLcafAddress.getGrpAddress()))
+                        .withGrpMaskLength(multiLcafAddress.getGrpMaskLength())
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case TRAFFIC_ENGINEERING:
+
+                LispTeLcafAddress teLcafAddress = (LispTeLcafAddress) lcaf;
+
+                List<LispTeAddress.TeRecord> records = Lists.newArrayList();
+
+                teLcafAddress.getTeRecords().forEach(record -> {
+                    LispTeAddress.TeRecord teRecord =
+                            new LispTeAddress.TeRecord.Builder()
+                                    .withIsLookup(record.isLookup())
+                                    .withIsRlocProbe(record.isRlocProbe())
+                                    .withIsStrict(record.isStrict())
+                                    .withRtrRlocAddress(getAddress(record.getRtrRlocAddress()))
+                                    .build();
+                    records.add(teRecord);
+                });
+
+                ema = new LispTeAddress.Builder()
+                        .withTeRecords(records)
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case SECURITY:
+
+                // TODO: need to implement security type later
+                log.warn("security type will be implemented later");
+
+                return null;
+
+            case SOURCE_DEST:
+
+                LispSourceDestLcafAddress srcDstLcafAddress = (LispSourceDestLcafAddress) lcaf;
+
+
+                ema = new LispSrcDstAddress.Builder()
+                        .withSrcPrefix(getAddress(srcDstLcafAddress.getSrcPrefix()))
+                        .withSrcMaskLength(srcDstLcafAddress.getSrcMaskLength())
+                        .withDstPrefix(getAddress(srcDstLcafAddress.getDstPrefix()))
+                        .withDstMaskLength(srcDstLcafAddress.getDstMaskLength())
+                        .build();
+
+                return MappingAddresses.extensionMappingAddressWrapper(ema, deviceId);
+
+            case UNSPECIFIED:
+            case UNKNOWN:
+            default:
+                log.error("Unsupported LCAF type {}", lcaf.getType());
+                return null;
+        }
+    }
+
+    /**
+     * Converts AFI address to generalized mapping address.
+     *
+     * @param afiAddress IP typed AFI address
+     * @return generalized mapping address
+     */
+    private MappingAddress afi2MappingAddress(LispAfiAddress afiAddress) {
+        switch (afiAddress.getAfi()) {
+            case IP4:
+                IpAddress ipv4Address = ((LispIpv4Address) afiAddress).getAddress();
+                IpPrefix ipv4Prefix = IpPrefix.valueOf(ipv4Address, IPV4_PREFIX_LENGTH);
+                return MappingAddresses.ipv4MappingAddress(ipv4Prefix);
+            case IP6:
+                IpAddress ipv6Address = ((LispIpv6Address) afiAddress).getAddress();
+                IpPrefix ipv6Prefix = IpPrefix.valueOf(ipv6Address, IPV6_PREFIX_LENGTH);
+                return MappingAddresses.ipv6MappingAddress(ipv6Prefix);
+            default:
+                log.warn("Only support to convert IP address type");
+                break;
+        }
+        return null;
+    }
+
+    /**
      * Builds a collection of mapping treatments.
      *
      * @param record LISP map record
@@ -232,14 +443,8 @@
         for (LispLocator locator : locators) {
             MappingTreatment.Builder builder = DefaultMappingTreatment.builder();
             LispAfiAddress address = locator.getLocatorAfi();
-            int addressLength = 0;
-            if (address.getAfi() == IP4) {
-                addressLength = IPV4_PREFIX_LENGTH;
-            } else if (address.getAfi() == IP6) {
-                addressLength = IPV6_PREFIX_LENGTH;
-            }
 
-            final MappingAddress mappingAddress = getAddress(address, addressLength);
+            final MappingAddress mappingAddress = getAddress(address);
             if (mappingAddress != null) {
                 builder.withAddress(mappingAddress);
             }
diff --git a/providers/lisp/mapping/src/test/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilderTest.java b/providers/lisp/mapping/src/test/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilderTest.java
index c6bf5fa..b78f167 100644
--- a/providers/lisp/mapping/src/test/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilderTest.java
+++ b/providers/lisp/mapping/src/test/java/org/onosproject/provider/lisp/mapping/util/MappingEntryBuilderTest.java
@@ -20,6 +20,15 @@
 import org.junit.Test;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onosproject.drivers.lisp.extensions.LispAppDataAddress;
+import org.onosproject.drivers.lisp.extensions.LispGcAddress;
+import org.onosproject.drivers.lisp.extensions.LispListAddress;
+import org.onosproject.drivers.lisp.extensions.LispMulticastAddress;
+import org.onosproject.drivers.lisp.extensions.LispNatAddress;
+import org.onosproject.drivers.lisp.extensions.LispNonceAddress;
+import org.onosproject.drivers.lisp.extensions.LispSegmentAddress;
+import org.onosproject.drivers.lisp.extensions.LispSrcDstAddress;
 import org.onosproject.lisp.msg.protocols.DefaultLispLocator.DefaultLocatorBuilder;
 import org.onosproject.lisp.msg.protocols.DefaultLispMapNotify.DefaultNotifyBuilder;
 import org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.DefaultMapRecordBuilder;
@@ -33,19 +42,58 @@
 import org.onosproject.lisp.msg.protocols.LispMapReply;
 import org.onosproject.lisp.msg.protocols.LispMapReply.ReplyBuilder;
 import org.onosproject.lisp.msg.protocols.LispMapReplyAction;
+import org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+import org.onosproject.lisp.msg.types.LispAsAddress;
+import org.onosproject.lisp.msg.types.LispDistinguishedNameAddress;
 import org.onosproject.lisp.msg.types.LispIpv4Address;
+import org.onosproject.lisp.msg.types.LispIpv6Address;
+import org.onosproject.lisp.msg.types.LispMacAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispAppDataLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispAsLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum;
+import org.onosproject.lisp.msg.types.lcaf.LispGeoCoordinateLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispListLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispMulticastLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispNatLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispNonceLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispSegmentLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispSourceDestLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispTeLcafAddress;
+import org.onosproject.lisp.msg.types.lcaf.LispTeRecord;
 import org.onosproject.mapping.MappingEntry;
 import org.onosproject.mapping.MappingKey;
 import org.onosproject.mapping.MappingTreatment;
 import org.onosproject.mapping.MappingValue;
 import org.onosproject.mapping.actions.MappingAction;
+import org.onosproject.mapping.addresses.ASMappingAddress;
+import org.onosproject.mapping.addresses.DNMappingAddress;
+import org.onosproject.mapping.addresses.EthMappingAddress;
+import org.onosproject.mapping.addresses.ExtensionMappingAddressWrapper;
 import org.onosproject.mapping.addresses.IPMappingAddress;
+import org.onosproject.mapping.addresses.MappingAddress;
 import org.onosproject.net.DeviceId;
 
 import java.util.List;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
+import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.AS;
+import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.DISTINGUISHED_NAME;
+import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.IP4;
+import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.IP6;
+import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.LCAF;
+import static org.onosproject.lisp.msg.types.AddressFamilyIdentifierEnum.MAC;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.APPLICATION_DATA;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.GEO_COORDINATE;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.LIST;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.MULTICAST;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.NAT;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.NONCE;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.SEGMENT;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.SOURCE_DEST;
+import static org.onosproject.lisp.msg.types.lcaf.LispCanonicalAddressFormatEnum.UNKNOWN;
 
 /**
  * Mapping entry builder unit test.
@@ -53,61 +101,230 @@
 public class MappingEntryBuilderTest {
 
     private static final String IP_RECORD_ADDRESS = "192.168.1.1";
-    private static final String IP_LOCATOR_ADDRESS = "10.1.1.1";
-    private static final int IP_RECORD_MASK_LENGTH = 24;
+    private static final int IP_RECORD_MASK_LENGTH = 32;
     private static final int IP_LOCATOR_MASK_LENGTH = 32;
 
+    private static final LispAfiAddress IPV4_ADDRESS_1 =
+                         new LispIpv4Address(IpAddress.valueOf("1.2.3.4"));
+    private static final LispAfiAddress IPV4_ADDRESS_2 =
+                         new LispIpv4Address(IpAddress.valueOf("5.6.7.8"));
+    private static final LispAfiAddress IPV6_ADDRESS =
+                         new LispIpv6Address(IpAddress.valueOf(
+                                 "1111:2222:3333:4444:5555:6666:7777:8885"));
+    private static final LispAfiAddress MAC_ADDRESS =
+                         new LispMacAddress(MacAddress.valueOf("00:00:00:00:00:01"));
+
+    private static final IpPrefix IPV4_MAPPING_ADDRESS_1 = IpPrefix.valueOf("1.2.3.4/32");
+    private static final IpPrefix IPV4_MAPPING_ADDRESS_2 = IpPrefix.valueOf("5.6.7.8/32");
+
+    private static final IpPrefix IPV6_MAPPING_ADDRESS =
+            IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/128");
+    private static final MacAddress MAC_MAPPING_ADDRESS =
+                                        MacAddress.valueOf("00:00:00:00:00:01");
+
+    private static final byte UNIQUE_BYTE = (byte) 0x01;
+    private static final int UNIQUE_INT = 1;
+    private static final short UNIQUE_SHORT = 1;
+    private static final boolean UNIQUE_BOOLEAN = true;
+    private static final long UNIQUE_LONG = 1L;
+    private static final String UNIQUE_STRING = "onos";
+
     private static final String AUTH_KEY = "onos";
 
-    private static final byte UNIQUE_VALUE = (byte) 0x01;
     private static final DeviceId DEVICE_ID = DeviceId.deviceId("lisp:10.1.1.2");
 
-    private LispMapReply mapReply;
-    private LispMapNotify mapNotify;
-
     @Before
     public void setUp() {
-        ReplyBuilder replyBuilder = new DefaultReplyBuilder();
 
-        List<LispMapRecord> records = ImmutableList.of(getMapRecord());
-
-        mapReply = replyBuilder
-                        .withIsEtr(true)
-                        .withIsProbe(false)
-                        .withIsSecurity(true)
-                        .withNonce(1L)
-                        .withMapRecords(records)
-                        .build();
-
-        NotifyBuilder notifyBuilder = new DefaultNotifyBuilder();
-
-        mapNotify = notifyBuilder
-                        .withKeyId((short) 1)
-                        .withAuthKey(AUTH_KEY)
-                        .withNonce(1L)
-                        .withMapRecords(records)
-                        .build();
     }
 
     @Test
     public void testMapReplyConversion() {
+
+        ReplyBuilder replyBuilder = new DefaultReplyBuilder();
+
+        List<LispMapRecord> records = ImmutableList.of(getMapRecord(IP4, UNKNOWN));
+
+        LispMapReply mapReply = replyBuilder
+                                    .withIsEtr(true)
+                                    .withIsProbe(false)
+                                    .withIsSecurity(true)
+                                    .withNonce(UNIQUE_LONG)
+                                    .withMapRecords(records)
+                                    .build();
+
         List<LispMapRecord> replyRecords = mapReply.getMapRecords();
 
         assertThat(replyRecords.size(), is(1));
 
-        testMapRecorConversion(replyRecords.get(0));
+        testMapRecordConversion(replyRecords.get(0));
     }
 
     @Test
     public void testMapNotifyConversion() {
+
+        List<LispMapRecord> records = ImmutableList.of(getMapRecord(IP4, UNKNOWN));
+
+        NotifyBuilder notifyBuilder = new DefaultNotifyBuilder();
+
+        LispMapNotify mapNotify = notifyBuilder
+                                    .withKeyId(UNIQUE_SHORT)
+                                    .withAuthKey(AUTH_KEY)
+                                    .withNonce(UNIQUE_LONG)
+                                    .withMapRecords(records)
+                                    .build();
+
         List<LispMapRecord> notifyRecords = mapNotify.getMapRecords();
 
         assertThat(notifyRecords.size(), is(1));
 
-        testMapRecorConversion(notifyRecords.get(0));
+        testMapRecordConversion(notifyRecords.get(0));
     }
 
-    private void testMapRecorConversion(LispMapRecord record) {
+    @Test
+    public void testIpv4AddressConversion() {
+        IPMappingAddress address = (IPMappingAddress) getMappingAddressByAfiType(IP4, UNKNOWN);
+        assertThat(address.ip(), is(IPV4_MAPPING_ADDRESS_1));
+    }
+
+    @Test
+    public void testIpv6AddressConversion() {
+        IPMappingAddress address = (IPMappingAddress) getMappingAddressByAfiType(IP6, UNKNOWN);
+        assertThat(address.ip(), is(IPV6_MAPPING_ADDRESS));
+    }
+
+    @Test
+    public void testMacAddressConversion() {
+        EthMappingAddress address = (EthMappingAddress) getMappingAddressByAfiType(MAC, UNKNOWN);
+        assertThat(address.mac(), is(MAC_MAPPING_ADDRESS));
+    }
+
+    @Test
+    public void testAsAddressConversion() {
+        ASMappingAddress address = (ASMappingAddress) getMappingAddressByAfiType(AS, UNKNOWN);
+        assertThat(address.asNumber(), is(String.valueOf(UNIQUE_INT)));
+    }
+
+    @Test
+    public void testDnAddressConversion() {
+        DNMappingAddress address = (DNMappingAddress)
+                        getMappingAddressByAfiType(DISTINGUISHED_NAME, UNKNOWN);
+        assertThat(address.name(), is(UNIQUE_STRING));
+    }
+
+    @Test
+    public void testListLcafAddressConversion() {
+        LispListAddress address = (LispListAddress) ((ExtensionMappingAddressWrapper)
+                getMappingAddressByAfiType(LCAF, LIST)).extensionMappingAddress();
+        assertThat(((IPMappingAddress) address.getIpv4()).ip(), is(IPV4_MAPPING_ADDRESS_1));
+        assertThat(((IPMappingAddress) address.getIpv6()).ip(), is(IPV6_MAPPING_ADDRESS));
+    }
+
+    @Test
+    public void testSegmentLcafAddressConversion() {
+        LispSegmentAddress address = (LispSegmentAddress) ((ExtensionMappingAddressWrapper)
+                getMappingAddressByAfiType(LCAF, SEGMENT)).extensionMappingAddress();
+        assertThat(((IPMappingAddress) address.getAddress()).ip(), is(IPV4_MAPPING_ADDRESS_1));
+        assertThat(address.getInstanceId(), is(UNIQUE_INT));
+    }
+
+    @Test
+    public void testAsLcafAddressConversion() {
+        org.onosproject.drivers.lisp.extensions.LispAsAddress address =
+                (org.onosproject.drivers.lisp.extensions.LispAsAddress)
+                ((ExtensionMappingAddressWrapper)
+                        getMappingAddressByAfiType(LCAF,
+                                LispCanonicalAddressFormatEnum.AS)).extensionMappingAddress();
+        assertThat(((IPMappingAddress) address.getAddress()).ip(), is(IPV4_MAPPING_ADDRESS_1));
+        assertThat(address.getAsNumber(), is(UNIQUE_INT));
+    }
+
+    @Test
+    public void testAppDataLcafAddressConversion() {
+        LispAppDataAddress address = (LispAppDataAddress) ((ExtensionMappingAddressWrapper)
+                getMappingAddressByAfiType(LCAF, APPLICATION_DATA)).extensionMappingAddress();
+        assertThat(((IPMappingAddress) address.getAddress()).ip(), is(IPV4_MAPPING_ADDRESS_1));
+        assertThat(address.getProtocol(), is(UNIQUE_BYTE));
+        assertThat(address.getIpTos(), is(UNIQUE_INT));
+        assertThat(address.getLocalPortLow(), is(UNIQUE_SHORT));
+        assertThat(address.getLocalPortHigh(), is(UNIQUE_SHORT));
+        assertThat(address.getRemotePortLow(), is(UNIQUE_SHORT));
+        assertThat(address.getRemotePortHigh(), is(UNIQUE_SHORT));
+    }
+
+    @Test
+    public void testGcLcafAddressConversion() {
+        LispGcAddress address = (LispGcAddress) ((ExtensionMappingAddressWrapper)
+                getMappingAddressByAfiType(LCAF, GEO_COORDINATE)).extensionMappingAddress();
+        assertThat(((IPMappingAddress) address.getAddress()).ip(), is(IPV4_MAPPING_ADDRESS_1));
+        assertThat(address.isNorth(), is(UNIQUE_BOOLEAN));
+        assertThat(address.getLatitudeDegree(), is(UNIQUE_SHORT));
+        assertThat(address.getLatitudeMinute(), is(UNIQUE_BYTE));
+        assertThat(address.getLatitudeSecond(), is(UNIQUE_BYTE));
+        assertThat(address.isEast(), is(UNIQUE_BOOLEAN));
+        assertThat(address.getLongitudeDegree(), is(UNIQUE_SHORT));
+        assertThat(address.getLongitudeMinute(), is(UNIQUE_BYTE));
+        assertThat(address.getLongitudeSecond(), is(UNIQUE_BYTE));
+        assertThat(address.getAltitude(), is(UNIQUE_INT));
+    }
+
+    @Test
+    public void testNatLcafAddressConversion() {
+        LispNatAddress address = (LispNatAddress) ((ExtensionMappingAddressWrapper)
+                getMappingAddressByAfiType(LCAF, NAT)).extensionMappingAddress();
+        assertThat(((IPMappingAddress)
+                address.getPrivateEtrRlocAddress()).ip(), is(IPV4_MAPPING_ADDRESS_1));
+        assertThat(((IPMappingAddress)
+                address.getGlobalEtrRlocAddress()).ip(), is(IPV4_MAPPING_ADDRESS_1));
+        assertThat(((IPMappingAddress)
+                address.getMsRlocAddress()).ip(), is(IPV4_MAPPING_ADDRESS_1));
+        assertThat(address.getEtrUdpPortNumber(), is(UNIQUE_SHORT));
+        assertThat(address.getMsUdpPortNumber(), is(UNIQUE_SHORT));
+        // TODO: need to compare RtrRlocAddresses
+    }
+
+    @Test
+    public void testNonceLcafAddressConversion() {
+        LispNonceAddress address = (LispNonceAddress) ((ExtensionMappingAddressWrapper)
+                getMappingAddressByAfiType(LCAF, NONCE)).extensionMappingAddress();
+        assertThat(((IPMappingAddress) address.getAddress()).ip(), is(IPV4_MAPPING_ADDRESS_1));
+        assertThat(address.getNonce(), is(UNIQUE_INT));
+    }
+
+    @Test
+    public void testMulticastLcafAddressConversion() {
+        LispMulticastAddress address = (LispMulticastAddress) ((ExtensionMappingAddressWrapper)
+                getMappingAddressByAfiType(LCAF, MULTICAST)).extensionMappingAddress();
+        assertThat(((IPMappingAddress) address.getSrcAddress()).ip(), is(IPV4_MAPPING_ADDRESS_1));
+        assertThat(((IPMappingAddress) address.getGrpAddress()).ip(), is(IPV4_MAPPING_ADDRESS_1));
+        assertThat(address.getInstanceId(), is(UNIQUE_INT));
+        assertThat(address.getSrcMaskLength(), is(UNIQUE_BYTE));
+        assertThat(address.getGrpMaskLength(), is(UNIQUE_BYTE));
+    }
+
+    @Test
+    public void testSrcDstLcafAddressConversion() {
+        LispSrcDstAddress address = (LispSrcDstAddress) ((ExtensionMappingAddressWrapper)
+                getMappingAddressByAfiType(LCAF, SOURCE_DEST)).extensionMappingAddress();
+        assertThat(((IPMappingAddress) address.getSrcPrefix()).ip(), is(IPV4_MAPPING_ADDRESS_1));
+        assertThat(((IPMappingAddress) address.getDstPrefix()).ip(), is(IPV4_MAPPING_ADDRESS_2));
+        assertThat(address.getSrcMaskLength(), is(UNIQUE_BYTE));
+        assertThat(address.getDstMaskLength(), is(UNIQUE_BYTE));
+    }
+
+    @Test
+    public void testTeLcafAddressConversion() {
+        // TODO: need to compare TeRecord list
+    }
+
+    private MappingAddress getMappingAddressByAfiType(AddressFamilyIdentifierEnum afiType,
+                                                      LispCanonicalAddressFormatEnum lcafType) {
+        LispMapRecord record = getMapRecord(afiType, lcafType);
+        MappingEntry entry = new MappingEntryBuilder(DEVICE_ID, record).build();
+        return entry.value().treatments().get(0).address();
+    }
+
+    private void testMapRecordConversion(LispMapRecord record) {
         MappingEntry mappingEntry =
                      new MappingEntryBuilder(DEVICE_ID, record).build();
         MappingKey key = mappingEntry.key();
@@ -125,11 +342,19 @@
         MappingTreatment treatment = value.treatments().get(0);
         IPMappingAddress locatorAddress = (IPMappingAddress) treatment.address();
 
-        assertThat(locatorAddress.ip(), is(IpPrefix.valueOf(IP_LOCATOR_ADDRESS + "/" +
+        assertThat(locatorAddress.ip(), is(IpPrefix.valueOf(IPV4_ADDRESS_1 + "/" +
                 IP_LOCATOR_MASK_LENGTH)));
     }
 
-    private LispMapRecord getMapRecord() {
+    /**
+     * Obtains a MapRecord instance.
+     *
+     * @param afiType   AFI address type
+     * @param lcafType  LCAF address type
+     * @return a MapRecord instance
+     */
+    private LispMapRecord getMapRecord(AddressFamilyIdentifierEnum afiType,
+                                       LispCanonicalAddressFormatEnum lcafType) {
         MapRecordBuilder recordBuilder = new DefaultMapRecordBuilder();
 
         LispIpv4Address recordAddress =
@@ -137,14 +362,13 @@
 
         LocatorBuilder locatorBuilder = new DefaultLocatorBuilder();
 
-        LispIpv4Address locatorAddress =
-                        new LispIpv4Address(IpAddress.valueOf(IP_LOCATOR_ADDRESS));
+        LispAfiAddress locatorAddress = getAfiAddress(afiType, lcafType);
 
-        LispLocator locator1 = locatorBuilder
-                                    .withPriority(UNIQUE_VALUE)
-                                    .withWeight(UNIQUE_VALUE)
-                                    .withMulticastPriority(UNIQUE_VALUE)
-                                    .withMulticastWeight(UNIQUE_VALUE)
+        LispLocator locator = locatorBuilder
+                                    .withPriority(UNIQUE_BYTE)
+                                    .withWeight(UNIQUE_BYTE)
+                                    .withMulticastPriority(UNIQUE_BYTE)
+                                    .withMulticastWeight(UNIQUE_BYTE)
                                     .withLocalLocator(true)
                                     .withRlocProbed(false)
                                     .withRouted(true)
@@ -152,13 +376,146 @@
                                     .build();
 
         return recordBuilder
-                .withRecordTtl(100)
+                .withRecordTtl(UNIQUE_INT)
                 .withIsAuthoritative(true)
-                .withMapVersionNumber((short) 1)
+                .withMapVersionNumber(UNIQUE_SHORT)
                 .withMaskLength((byte) IP_RECORD_MASK_LENGTH)
                 .withAction(LispMapReplyAction.NativelyForward)
                 .withEidPrefixAfi(recordAddress)
-                .withLocators(ImmutableList.of(locator1))
+                .withLocators(ImmutableList.of(locator))
                 .build();
     }
+
+    /**
+     * Obtains the AFI address with respect to the AFI address type.
+     *
+     * @param afiType   AFI address type
+     * @param lcafType  LCAF address type
+     * @return AFI address instance
+     */
+    private LispAfiAddress getAfiAddress(AddressFamilyIdentifierEnum afiType,
+                                         LispCanonicalAddressFormatEnum lcafType) {
+        switch (afiType) {
+            case IP4:
+                return IPV4_ADDRESS_1;
+            case IP6:
+                return IPV6_ADDRESS;
+            case AS:
+                return new LispAsAddress(UNIQUE_INT);
+            case DISTINGUISHED_NAME:
+                return new LispDistinguishedNameAddress(UNIQUE_STRING);
+            case MAC:
+                return MAC_ADDRESS;
+            case LCAF:
+                return getLcafAddress(lcafType);
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Obtains the LCAF address with respect to the LCAF type.
+     *
+     * @param type LCAF type
+     * @return LCAF address instance
+     */
+    private LispLcafAddress getLcafAddress(LispCanonicalAddressFormatEnum type) {
+
+        List<LispAfiAddress> afiAddresses =
+                                    ImmutableList.of(IPV4_ADDRESS_1, IPV6_ADDRESS);
+
+        switch (type) {
+            case LIST:
+                return new LispListLcafAddress(afiAddresses);
+            case SEGMENT:
+                return new LispSegmentLcafAddress.SegmentAddressBuilder()
+                                    .withIdMaskLength(UNIQUE_BYTE)
+                                    .withInstanceId(UNIQUE_INT)
+                                    .withAddress(IPV4_ADDRESS_1)
+                                    .build();
+            case AS:
+                return new LispAsLcafAddress.AsAddressBuilder()
+                                    .withAsNumber(UNIQUE_INT)
+                                    .withAddress(IPV4_ADDRESS_1)
+                                    .build();
+            case APPLICATION_DATA:
+                return new LispAppDataLcafAddress.AppDataAddressBuilder()
+                                    .withProtocol(UNIQUE_BYTE)
+                                    .withIpTos(UNIQUE_SHORT)
+                                    .withLocalPortLow(UNIQUE_SHORT)
+                                    .withLocalPortHigh(UNIQUE_SHORT)
+                                    .withRemotePortLow(UNIQUE_SHORT)
+                                    .withRemotePortHigh(UNIQUE_SHORT)
+                                    .withAddress(IPV4_ADDRESS_1)
+                                    .build();
+            case GEO_COORDINATE:
+                return new LispGeoCoordinateLcafAddress.GeoCoordinateAddressBuilder()
+                                    .withIsNorth(UNIQUE_BOOLEAN)
+                                    .withLatitudeDegree(UNIQUE_SHORT)
+                                    .withLatitudeMinute(UNIQUE_BYTE)
+                                    .withLatitudeSecond(UNIQUE_BYTE)
+                                    .withIsEast(UNIQUE_BOOLEAN)
+                                    .withLongitudeDegree(UNIQUE_SHORT)
+                                    .withLongitudeMinute(UNIQUE_BYTE)
+                                    .withLongitudeSecond(UNIQUE_BYTE)
+                                    .withAltitude(UNIQUE_INT)
+                                    .withAddress(IPV4_ADDRESS_1)
+                                    .build();
+            case NAT:
+                return new LispNatLcafAddress.NatAddressBuilder()
+                                    .withLength(UNIQUE_SHORT)
+                                    .withMsUdpPortNumber(UNIQUE_SHORT)
+                                    .withEtrUdpPortNumber(UNIQUE_SHORT)
+                                    .withGlobalEtrRlocAddress(IPV4_ADDRESS_1)
+                                    .withMsRlocAddress(IPV4_ADDRESS_1)
+                                    .withPrivateEtrRlocAddress(IPV4_ADDRESS_1)
+                                    .withRtrRlocAddresses(afiAddresses)
+                                    .build();
+            case NONCE:
+                return new LispNonceLcafAddress.NonceAddressBuilder()
+                                    .withNonce(UNIQUE_INT)
+                                    .withAddress(IPV4_ADDRESS_1)
+                                    .build();
+            case MULTICAST:
+                return new LispMulticastLcafAddress.MulticastAddressBuilder()
+                                    .withInstanceId(UNIQUE_INT)
+                                    .withSrcMaskLength(UNIQUE_BYTE)
+                                    .withGrpMaskLength(UNIQUE_BYTE)
+                                    .withSrcAddress(IPV4_ADDRESS_1)
+                                    .withGrpAddress(IPV4_ADDRESS_1)
+                                    .build();
+            case TRAFFIC_ENGINEERING:
+                LispTeRecord.TeRecordBuilder recordBuilder1 = new LispTeRecord.TeRecordBuilder();
+
+                recordBuilder1.withIsLookup(UNIQUE_BOOLEAN);
+                recordBuilder1.withIsRlocProbe(UNIQUE_BOOLEAN);
+                recordBuilder1.withIsStrict(UNIQUE_BOOLEAN);
+                recordBuilder1.withRtrRlocAddress(IPV4_ADDRESS_1);
+                LispTeRecord record1 = recordBuilder1.build();
+
+                LispTeRecord.TeRecordBuilder recordBuilder2 = new LispTeRecord.TeRecordBuilder();
+
+                recordBuilder2.withIsLookup(UNIQUE_BOOLEAN);
+                recordBuilder2.withIsRlocProbe(UNIQUE_BOOLEAN);
+                recordBuilder2.withIsStrict(UNIQUE_BOOLEAN);
+                recordBuilder2.withRtrRlocAddress(IPV4_ADDRESS_2);
+                LispTeRecord record2 = recordBuilder2.build();
+
+                return new LispTeLcafAddress.TeAddressBuilder()
+                                    .withTeRecords(ImmutableList.of(record1, record2))
+                                    .build();
+            case SOURCE_DEST:
+                return new LispSourceDestLcafAddress.SourceDestAddressBuilder()
+                                    .withReserved(UNIQUE_SHORT)
+                                    .withSrcMaskLength(UNIQUE_BYTE)
+                                    .withDstMaskLength(UNIQUE_BYTE)
+                                    .withSrcPrefix(IPV4_ADDRESS_1)
+                                    .withDstPrefix(IPV4_ADDRESS_2)
+                                    .build();
+            case UNKNOWN:
+            case UNSPECIFIED:
+            default:
+                return null;
+        }
+    }
 }