class ArpDecoder extends AbstractPacketDecoder<EthernetPacketReceived, ArpPacketReceived> implements EthernetPacketListener {

    @Override
    public ArpPacketReceived decode(EthernetPacketReceived ethernetPacketReceived) {
        ArpPacketReceivedBuilder arpReceivedBuilder = new ArpPacketReceivedBuilder();

        // Find the latest packet in the packet-chain, which is an
        // EthernetPacket
        List<PacketChain> packetChainList = ethernetPacketReceived.getPacketChain();
        EthernetPacket ethernetPacket = (EthernetPacket) packetChainList.get(packetChainList.size() - 1).getPacket();
        int bitOffset = ethernetPacket.getPayloadOffset() * NetUtils.NUM_BITS_IN_A_BYTE;
        byte[] data = ethernetPacketReceived.getPayload();

        ArpPacketBuilder builder = new ArpPacketBuilder();
        try {
            // Decode the hardware-type (HTYPE) and protocol-type (PTYPE) fields
            builder.setHardwareType(KnownHardwareType
                    .forValue(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset + 0, 16))));
            builder.setProtocolType(
                    KnownEtherType.forValue(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset + 16, 16))));

            // Decode the hardware-length and protocol-length fields
            builder.setHardwareLength(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset + 32, 8)));
            builder.setProtocolLength(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset + 40, 8)));

            // Decode the operation field
            builder.setOperation(
                    KnownOperation.forValue(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset + 48, 16))));

            // Decode the address fields
            int indexSrcProtAdd = 64 + 8 * builder.getHardwareLength();
            int indexDstHardAdd = indexSrcProtAdd + 8 * builder.getProtocolLength();
            int indexDstProtAdd = indexDstHardAdd + 8 * builder.getHardwareLength();
            if (builder.getHardwareType().equals(KnownHardwareType.Ethernet)) {
                builder.setSourceHardwareAddress(HexEncode.bytesToHexStringFormat(
                        BitBufferHelper.getBits(data, bitOffset + 64, 8 * builder.getHardwareLength())));
                builder.setDestinationHardwareAddress(HexEncode.bytesToHexStringFormat(
                        BitBufferHelper.getBits(data, bitOffset + indexDstHardAdd, 8 * builder.getHardwareLength())));
            } else {
                LOG.debug(
                        "Unknown HardwareType -- sourceHardwareAddress and destinationHardwareAddress are not decoded");
            }

            if (builder.getProtocolType().equals(KnownEtherType.Ipv4)
                    || builder.getProtocolType().equals(KnownEtherType.Ipv6)) {
                builder.setSourceProtocolAddress(InetAddress.getByAddress(
                        BitBufferHelper.getBits(data, bitOffset + indexSrcProtAdd, 8 * builder.getProtocolLength()))
                        .getHostAddress());
                builder.setDestinationProtocolAddress(InetAddress.getByAddress(
                        BitBufferHelper.getBits(data, bitOffset + indexDstProtAdd, 8 * builder.getProtocolLength()))
                        .getHostAddress());
            } else {
                LOG.debug(
                        "Unknown ProtocolType -- sourceProtocolAddress and destinationProtocolAddress are not decoded");
            }
        } catch (BufferException | UnknownHostException e) {
            LOG.debug("Exception while decoding APR packet", e.getMessage());
        }

        // build arp
        packetChainList.add(new PacketChainBuilder().setPacket(builder.build()).build());
        arpReceivedBuilder.setPacketChain(packetChainList);

        // carry forward the original payload.
        arpReceivedBuilder.setPayload(ethernetPacketReceived.getPayload());

        return arpReceivedBuilder.build();
    }

    public  ArpDecoder(NotificationProviderService notificationProviderService);

}