[ONOS-4718] Initial implementation of LISP control msg serializer

Change-Id: Ia068e1b158f05dd70839cb1020f15dc66b0142a0
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java
index 7f75181..abaf3c8 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapRegister.java
@@ -23,11 +23,14 @@
 import org.onlab.util.ImmutableByteSequence;
 import org.onosproject.lisp.msg.exceptions.LispParseError;
 import org.onosproject.lisp.msg.exceptions.LispReaderException;
+import org.onosproject.lisp.msg.exceptions.LispWriterException;
 
+import java.util.Arrays;
 import java.util.List;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 
+
 /**
  * Default LISP map register message class.
  */
@@ -35,6 +38,7 @@
 
     private final long nonce;
     private final short keyId;
+    private final short authDataLength;
     private final byte[] authenticationData;
     private final byte recordCount;
     private final List<LispMapRecord> mapRecords;
@@ -52,12 +56,13 @@
      * @param proxyMapReply      proxy map reply flag
      * @param wantMapNotify      want map notify flag
      */
-    private DefaultLispMapRegister(long nonce, short keyId,
+    private DefaultLispMapRegister(long nonce, short keyId, short authDataLength,
                                    byte[] authenticationData, byte recordCount,
                                    List<LispMapRecord> mapRecords,
                                    boolean proxyMapReply, boolean wantMapNotify) {
         this.nonce = nonce;
         this.keyId = keyId;
+        this.authDataLength = authDataLength;
         this.authenticationData = authenticationData;
         this.recordCount = recordCount;
         this.mapRecords = mapRecords;
@@ -106,6 +111,11 @@
     }
 
     @Override
+    public short getAuthDataLength() {
+        return authDataLength;
+    }
+
+    @Override
     public byte[] getAuthenticationData() {
         return ImmutableByteSequence.copyFrom(this.authenticationData).asArray();
     }
@@ -122,6 +132,8 @@
                 .add("nonce", nonce)
                 .add("recordCount", recordCount)
                 .add("keyId", keyId)
+                .add("authentication data length", authDataLength)
+                .add("authentication data", authenticationData)
                 .add("mapRecords", mapRecords)
                 .add("proxyMapReply", proxyMapReply)
                 .add("wantMapNotify", wantMapNotify).toString();
@@ -140,6 +152,7 @@
         return Objects.equal(nonce, that.nonce) &&
                 Objects.equal(recordCount, that.recordCount) &&
                 Objects.equal(keyId, that.keyId) &&
+                Objects.equal(authDataLength, that.authDataLength) &&
                 Objects.equal(authenticationData, that.authenticationData) &&
                 Objects.equal(proxyMapReply, that.proxyMapReply) &&
                 Objects.equal(wantMapNotify, that.wantMapNotify);
@@ -147,14 +160,15 @@
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(nonce, recordCount, keyId, authenticationData,
-                                proxyMapReply, wantMapNotify);
+        return Objects.hashCode(nonce, recordCount, keyId, authDataLength,
+                authenticationData, proxyMapReply, wantMapNotify);
     }
 
     public static final class DefaultRegisterBuilder implements RegisterBuilder {
 
         private long nonce;
         private short keyId;
+        private short authDataLength;
         private byte[] authenticationData;
         private byte recordCount;
         private List<LispMapRecord> mapRecords;
@@ -191,6 +205,12 @@
         }
 
         @Override
+        public RegisterBuilder withAuthDataLength(short authDataLength) {
+            this.authDataLength = authDataLength;
+            return this;
+        }
+
+        @Override
         public RegisterBuilder withKeyId(short keyId) {
             this.keyId = keyId;
             return this;
@@ -210,15 +230,15 @@
 
         @Override
         public LispMapRegister build() {
-            return new DefaultLispMapRegister(nonce, keyId, authenticationData,
-                    recordCount, mapRecords, proxyMapReply, wantMapNotify);
+            return new DefaultLispMapRegister(nonce, keyId, authDataLength,
+                    authenticationData, recordCount, mapRecords, proxyMapReply, wantMapNotify);
         }
     }
 
     /**
-     * A private LISP message reader for MapRegister message.
+     * A LISP message reader for MapRegister message.
      */
-    private static class RegisterReader implements LispMessageReader<LispMapRegister> {
+    public static final class RegisterReader implements LispMessageReader<LispMapRegister> {
 
         private static final int PROXY_MAP_REPLY_INDEX = 3;
         private static final int WANT_MAP_NOTIFY_INDEX = 0;
@@ -274,4 +294,78 @@
                     .build();
         }
     }
+
+    /**
+     * LISP map register message writer class.
+     */
+    public static class RegisterWriter implements LispMessageWriter<LispMapRegister> {
+
+        private static final int REGISTER_MSG_TYPE = 3;
+        private static final int REGISTER_SHIFT_BIT = 4;
+
+        private static final int PROXY_MAP_REPLY_SHIFT_BIT = 3;
+
+        private static final int ENABLE_BIT = 1;
+        private static final int DISABLE_BIT = 0;
+
+        private static final int UNUSED_ZERO = 0;
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispMapRegister message) throws LispWriterException {
+
+            // specify LISP message type
+            byte msgType = (byte) (REGISTER_MSG_TYPE << REGISTER_SHIFT_BIT);
+
+            // proxy map reply flag
+            byte proxyMapReply = DISABLE_BIT;
+            if (message.isProxyMapReply())  {
+                proxyMapReply = (byte) (ENABLE_BIT << PROXY_MAP_REPLY_SHIFT_BIT);
+            }
+
+            byteBuf.writeByte(msgType + proxyMapReply);
+
+            // fill zero into reserved field
+            byteBuf.writeByte((short) UNUSED_ZERO);
+
+            // want map notify flag
+            byte wantMapNotify = DISABLE_BIT;
+            if (message.isWantMapNotify()) {
+                wantMapNotify = (byte) ENABLE_BIT;
+            }
+
+            byteBuf.writeByte(wantMapNotify);
+
+            // record count
+            byteBuf.writeByte(message.getRecordCount());
+
+            // nonce
+            byteBuf.writeLong(message.getNonce());
+
+            // keyId
+            byteBuf.writeShort(message.getKeyId());
+
+            // authentication data length in octet
+            byteBuf.writeShort(message.getAuthDataLength());
+
+            // authentication data
+            byte[] data = message.getAuthenticationData();
+            byte[] clone;
+            if (data != null) {
+                clone = data.clone();
+                Arrays.fill(clone, (byte) UNUSED_ZERO);
+            }
+
+            byteBuf.writeBytes(data);
+
+            // TODO: need to implement MAC authentication mechanism
+
+            // serialize map records
+            DefaultLispMapRecord.MapRecordWriter writer = new DefaultLispMapRecord.MapRecordWriter();
+            List<LispMapRecord> records = message.getMapRecords();
+
+            for (int i = 0; i < records.size(); i++) {
+                writer.writeTo(byteBuf, records.get(i));
+            }
+        }
+    }
 }