[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/DefaultLispMapNotify.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java
index 05cc7f5..30eba1f 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispMapNotify.java
@@ -22,10 +22,13 @@
 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;
+import static org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.MapRecordWriter;
 
 /**
  * Default LISP map notify message class.
@@ -34,6 +37,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;
@@ -47,10 +51,12 @@
      * @param recordCount        record count number
      * @param mapRecords         a collection of map records
      */
-    private DefaultLispMapNotify(long nonce, short keyId, byte[] authenticationData,
-                                 byte recordCount, List<LispMapRecord> mapRecords) {
+    private DefaultLispMapNotify(long nonce, short keyId, short authDataLength,
+                                 byte[] authenticationData, byte recordCount,
+                                 List<LispMapRecord> mapRecords) {
         this.nonce = nonce;
         this.keyId = keyId;
+        this.authDataLength = authDataLength;
         this.authenticationData = authenticationData;
         this.recordCount = recordCount;
         this.mapRecords = mapRecords;
@@ -73,26 +79,31 @@
 
     @Override
     public long getNonce() {
-        return this.nonce;
+        return nonce;
     }
 
     @Override
     public byte getRecordCount() {
-        return this.recordCount;
+        return recordCount;
     }
 
     @Override
     public short getKeyId() {
-        return this.keyId;
+        return keyId;
+    }
+
+    @Override
+    public short getAuthDataLength() {
+        return authDataLength;
     }
 
     @Override
     public byte[] getAuthenticationData() {
-        return ImmutableByteSequence.copyFrom(this.authenticationData).asArray();
+        return ImmutableByteSequence.copyFrom(authenticationData).asArray();
     }
 
     @Override
-    public List<LispMapRecord> getLispRecords() {
+    public List<LispMapRecord> getMapRecords() {
         return ImmutableList.copyOf(mapRecords);
     }
 
@@ -103,6 +114,8 @@
                 .add("nonce", nonce)
                 .add("recordCount", recordCount)
                 .add("keyId", keyId)
+                .add("authentication data length", authDataLength)
+                .add("authentication data", authenticationData)
                 .add("mapRecords", mapRecords).toString();
     }
 
@@ -118,18 +131,20 @@
         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);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(nonce, recordCount, keyId, authenticationData);
+        return Objects.hashCode(nonce, recordCount, keyId, authDataLength, authenticationData);
     }
 
     public static final class DefaultNotifyBuilder implements NotifyBuilder {
 
         private long nonce;
         private short keyId;
+        private short authDataLength;
         private byte[] authenticationData;
         private byte recordCount;
         private List<LispMapRecord> mapRecords;
@@ -158,6 +173,12 @@
         }
 
         @Override
+        public NotifyBuilder withAuthDataLength(short authDataLength) {
+            this.authDataLength = authDataLength;
+            return this;
+        }
+
+        @Override
         public NotifyBuilder withAuthenticationData(byte[] authenticationData) {
             this.authenticationData = authenticationData;
             return this;
@@ -171,15 +192,15 @@
 
         @Override
         public LispMapNotify build() {
-            return new DefaultLispMapNotify(nonce, keyId, authenticationData,
-                    recordCount, mapRecords);
+            return new DefaultLispMapNotify(nonce, keyId, authDataLength,
+                    authenticationData, recordCount, mapRecords);
         }
     }
 
     /**
-     * A private LISP message reader for MapNotify message.
+     * A LISP message reader for MapNotify message.
      */
-    private static class NotifyReader implements LispMessageReader<LispMapNotify> {
+    public static final class NotifyReader implements LispMessageReader<LispMapNotify> {
 
         private static final int RESERVED_SKIP_LENGTH = 3;
 
@@ -218,9 +239,64 @@
                         .withRecordCount(recordCount)
                         .withNonce(nonce)
                         .withKeyId(keyId)
+                        .withAuthDataLength(authLength)
                         .withAuthenticationData(authData)
                         .withMapRecords(mapRecords)
                         .build();
         }
     }
+
+    /**
+     * A LISP message reader for MapNotify message.
+     */
+    public static final class NotifyWriter implements LispMessageWriter<LispMapNotify> {
+
+        private static final int NOTIFY_MSG_TYPE = 4;
+        private static final int NOTIFY_SHIFT_BIT = 4;
+
+        private static final int UNUSED_ZERO = 0;
+
+        @Override
+        public void writeTo(ByteBuf byteBuf, LispMapNotify message) throws LispWriterException {
+
+            // specify LISP message type
+            byte msgType = (byte) (NOTIFY_MSG_TYPE << NOTIFY_SHIFT_BIT);
+            byteBuf.writeByte(msgType);
+
+            // reserved field
+            byteBuf.writeShort((short) UNUSED_ZERO);
+
+            // 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
+            MapRecordWriter writer = new MapRecordWriter();
+            List<LispMapRecord> records = message.getMapRecords();
+
+            for (int i = 0; i < records.size(); i++) {
+                writer.writeTo(byteBuf, records.get(i));
+            }
+        }
+    }
 }