ONOS-2739 - OSPF Basic Packet Structures , which includes encoding and decoding

Change-Id: Ic37fcf98dfb6c7a15a124b495aee8517a8df23c9
diff --git a/protocols/ospf/protocol/src/main/java/org/onosproject/ospf/protocol/lsa/tlvtypes/LinkTlv.java b/protocols/ospf/protocol/src/main/java/org/onosproject/ospf/protocol/lsa/tlvtypes/LinkTlv.java
new file mode 100644
index 0000000..aaf66da
--- /dev/null
+++ b/protocols/ospf/protocol/src/main/java/org/onosproject/ospf/protocol/lsa/tlvtypes/LinkTlv.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * 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.onosproject.ospf.protocol.lsa.tlvtypes;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.primitives.Bytes;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.ospf.protocol.lsa.TlvHeader;
+import org.onosproject.ospf.protocol.lsa.linksubtype.AdministrativeGroup;
+import org.onosproject.ospf.protocol.lsa.linksubtype.LinkId;
+import org.onosproject.ospf.protocol.lsa.linksubtype.LinkSubType;
+import org.onosproject.ospf.protocol.lsa.linksubtype.LinkSubTypes;
+import org.onosproject.ospf.protocol.lsa.linksubtype.LinkType;
+import org.onosproject.ospf.protocol.lsa.linksubtype.LocalInterfaceIpAddress;
+import org.onosproject.ospf.protocol.lsa.linksubtype.MaximumBandwidth;
+import org.onosproject.ospf.protocol.lsa.linksubtype.MaximumReservableBandwidth;
+import org.onosproject.ospf.protocol.lsa.linksubtype.RemoteInterfaceIpAddress;
+import org.onosproject.ospf.protocol.lsa.linksubtype.TrafficEngineeringMetric;
+import org.onosproject.ospf.protocol.lsa.linksubtype.UnknownLinkSubType;
+import org.onosproject.ospf.protocol.lsa.linksubtype.UnreservedBandwidth;
+import org.onosproject.ospf.protocol.lsa.types.TopLevelTlv;
+import org.onosproject.ospf.protocol.util.OspfUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Representation of an OSPF Opaque link tlv.
+ */
+public class LinkTlv extends TlvHeader implements TopLevelTlv {
+    private List<LinkSubType> subTlv = new ArrayList<>();
+
+    /**
+     * Creates an instance of link tlv.
+     *
+     * @param header tlv header
+     */
+    public LinkTlv(TlvHeader header) {
+        this.setTlvType(header.tlvType());
+        this.setTlvLength(header.tlvLength());
+    }
+
+    /**
+     * Gets sub tlv lists.
+     *
+     * @return sub tlv lists
+     */
+    public List<LinkSubType> subTlvList() {
+        return this.subTlv;
+    }
+
+    /**
+     * Reads bytes from channel buffer .
+     *
+     * @param channelBuffer channel buffer instance
+     * @throws Exception might throws exception while parsing packet
+     */
+    public void readFrom(ChannelBuffer channelBuffer) throws Exception {
+        while (channelBuffer.readableBytes() > 0) {
+            TlvHeader tlvHeader = new TlvHeader();
+            tlvHeader.setTlvType(channelBuffer.readUnsignedShort());
+            tlvHeader.setTlvLength(channelBuffer.readUnsignedShort());
+
+            if (LinkSubTypes.LINK_TYPE.value() == tlvHeader.tlvType()) {
+                LinkType linktype = new LinkType(tlvHeader);
+                linktype.readFrom(channelBuffer.readBytes(tlvHeader.tlvLength()));
+                subTlv.add(linktype);
+                if (tlvHeader.tlvLength() < OspfUtil.FOUR_BYTES) {
+                    int readerIndex = channelBuffer.readerIndex() + (OspfUtil.FOUR_BYTES - tlvHeader.tlvLength());
+                    channelBuffer.readerIndex(readerIndex);
+                }
+            } else if (LinkSubTypes.LINK_ID.value() == tlvHeader.tlvType()) {
+                LinkId linkId = new LinkId(tlvHeader);
+                linkId.readFrom(channelBuffer.readBytes(tlvHeader.tlvLength()));
+                subTlv.add(linkId);
+            } else if (LinkSubTypes.LOCAL_INTERFACE_IP_ADDRESS.value() == tlvHeader.tlvType()) {
+                LocalInterfaceIpAddress localInterfaceIpAddress = new LocalInterfaceIpAddress(tlvHeader);
+                localInterfaceIpAddress.readFrom(channelBuffer.readBytes(tlvHeader.tlvLength()));
+                subTlv.add(localInterfaceIpAddress);
+            } else if (LinkSubTypes.REMOTE_INTERFACE_IP_ADDRESS.value() == tlvHeader.tlvType()) {
+                RemoteInterfaceIpAddress remoteInterfaceIpAddress = new RemoteInterfaceIpAddress(tlvHeader);
+                remoteInterfaceIpAddress.readFrom(channelBuffer.readBytes(tlvHeader.tlvLength()));
+                subTlv.add(remoteInterfaceIpAddress);
+            } else if (LinkSubTypes.TRAFFIC_ENGINEERING_METRIC.value() == tlvHeader.tlvType()) {
+                TrafficEngineeringMetric trafficEngineeringMetric = new TrafficEngineeringMetric(tlvHeader);
+                trafficEngineeringMetric.readFrom(channelBuffer.readBytes(tlvHeader.tlvLength()));
+                subTlv.add(trafficEngineeringMetric);
+            } else if (LinkSubTypes.MAXIMUM_BANDWIDTH.value() == tlvHeader.tlvType()) {
+                MaximumBandwidth maximumBandwidth = new MaximumBandwidth(tlvHeader);
+                maximumBandwidth.readFrom(channelBuffer.readBytes(tlvHeader.tlvLength()));
+                subTlv.add(maximumBandwidth);
+            } else if (LinkSubTypes.MAXIMUM_RESERVABLE_BANDWIDTH.value() == tlvHeader.tlvType()) {
+                MaximumReservableBandwidth maximumReservableBandwidth = new MaximumReservableBandwidth(tlvHeader);
+                maximumReservableBandwidth.readFrom(channelBuffer.readBytes(tlvHeader.tlvLength()));
+                subTlv.add(maximumReservableBandwidth);
+            } else if (LinkSubTypes.UNRESERVED_BANDWIDTH.value() == tlvHeader.tlvType()) {
+                UnreservedBandwidth unreservedBandwidth = new UnreservedBandwidth(tlvHeader);
+                unreservedBandwidth.readFrom(channelBuffer.readBytes(tlvHeader.tlvLength()));
+                subTlv.add(unreservedBandwidth);
+            } else if (LinkSubTypes.ADMINISTRATIVE_GROUP.value() == tlvHeader.tlvType()) {
+                AdministrativeGroup administrativeGroup = new AdministrativeGroup(tlvHeader);
+                administrativeGroup.readFrom(channelBuffer.readBytes(tlvHeader.tlvLength()));
+                subTlv.add(administrativeGroup);
+            } else {
+                UnknownLinkSubType unknownLinkSubType = new UnknownLinkSubType(tlvHeader);
+                unknownLinkSubType.readFrom(channelBuffer.readBytes(tlvHeader.tlvLength()));
+                subTlv.add(unknownLinkSubType);
+            }
+        }
+    }
+
+    /**
+     * Gets link tlv as byte array.
+     *
+     * @return link tlv as byte array
+     * @throws Exception might throws exception while parsing buffer
+     */
+    public byte[] asBytes() throws Exception {
+        byte[] lsaMessage = null;
+
+        byte[] tlvHeader = getTlvHeaderAsByteArray();
+        byte[] tlvBody = getTlvBodyAsByteArray();
+        lsaMessage = Bytes.concat(tlvHeader, tlvBody);
+
+        return lsaMessage;
+    }
+
+    /**
+     * Gets tlv body as byte array.
+     *
+     * @return tlv body as byte array
+     * @throws Exception might throws exception while parsing buffer
+     */
+    public byte[] getTlvBodyAsByteArray() throws Exception {
+
+        List<Byte> bodyLst = new ArrayList<>();
+        for (LinkSubType tlv : subTlv) {
+            //Check the type of tlv and build bytes accordingly
+            if (tlv instanceof LinkType) {
+                LinkType linkType = (LinkType) tlv;
+                bodyLst.addAll(Bytes.asList(linkType.asBytes()));
+            } else if (tlv instanceof LinkId) {
+                LinkId linkId = (LinkId) tlv;
+                bodyLst.addAll(Bytes.asList(linkId.asBytes()));
+            } else if (tlv instanceof LocalInterfaceIpAddress) {
+                LocalInterfaceIpAddress localInterfaceIpAddress = (LocalInterfaceIpAddress) tlv;
+                bodyLst.addAll(Bytes.asList(localInterfaceIpAddress.asBytes()));
+            } else if (tlv instanceof RemoteInterfaceIpAddress) {
+                RemoteInterfaceIpAddress remoteInterfaceIpAddress = (RemoteInterfaceIpAddress) tlv;
+                bodyLst.addAll(Bytes.asList(remoteInterfaceIpAddress.asBytes()));
+            } else if (tlv instanceof TrafficEngineeringMetric) {
+                TrafficEngineeringMetric trafficEngineeringMetric = (TrafficEngineeringMetric) tlv;
+                bodyLst.addAll(Bytes.asList(trafficEngineeringMetric.asBytes()));
+            } else if (tlv instanceof MaximumBandwidth) {
+                MaximumBandwidth maximumBandwidth = (MaximumBandwidth) tlv;
+                bodyLst.addAll(Bytes.asList(maximumBandwidth.asBytes()));
+            } else if (tlv instanceof MaximumReservableBandwidth) {
+                MaximumReservableBandwidth maximumReservableBandwidth = (MaximumReservableBandwidth) tlv;
+                bodyLst.addAll(Bytes.asList(maximumReservableBandwidth.asBytes()));
+            } else if (tlv instanceof UnreservedBandwidth) {
+                UnreservedBandwidth unreservedBandwidth = (UnreservedBandwidth) tlv;
+                bodyLst.addAll(Bytes.asList(unreservedBandwidth.asBytes()));
+            } else if (tlv instanceof AdministrativeGroup) {
+                AdministrativeGroup administrativeGroup = (AdministrativeGroup) tlv;
+                bodyLst.addAll(Bytes.asList(administrativeGroup.asBytes()));
+            } else {
+                UnknownLinkSubType unknownLinkSubType = (UnknownLinkSubType) tlv;
+                bodyLst.addAll(Bytes.asList(unknownLinkSubType.asBytes()));
+            }
+        }
+        return Bytes.toArray(bodyLst);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .omitNullValues()
+                .add("subTlv", subTlv)
+                .toString();
+    }
+}
\ No newline at end of file