com.xsdn.main.util.EtherAddress.java Source code

Java tutorial

Introduction

Here is the source code for com.xsdn.main.util.EtherAddress.java

Source

/*
 * Copyright (c) 2015 NEC Corporation
 * All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 */

package com.xsdn.main.util;

/**
 * Created by fortitude on 15-9-16.
 */

import java.io.Serializable;
import java.util.Arrays;
import java.util.Locale;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlValue;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import org.opendaylight.controller.sal.packet.address.EthernetAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.MacAddressFilter;

import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;

/**
 * {@code EtherAddress} describes an ethernet address, aka MAC address.
 *
 * @since  Lithium
 */
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
@XmlRootElement(name = "ether-address")
@XmlAccessorType(XmlAccessType.NONE)
public final class EtherAddress implements Serializable {
    /**
     * Version number for serialization.
     */
    private static final long serialVersionUID = -5338324896227836920L;

    /**
     * The number of octets in an ethernet address.
     */
    public static final int SIZE = 6;

    /**
     * Multicast bit in the first octet.
     */
    public static final int BIT_MULTICAST = 0x1;

    /**
     * A mask value that indicates the multicast bit in the first octet.
     */
    public static final long MASK_MULTICAST = ((long) BIT_MULTICAST << ((SIZE - 1) * Byte.SIZE));

    /**
     * A {@link EtherAddress} instance which represents a broadcast address.
     */
    public static final EtherAddress BROADCAST = new EtherAddress(0xffffffffffffL);

    /**
     * A long integer value which represents an ethernet address.
     */
    private long address;

    /**
     * An byte array which represents an ethernet address.
     */
    private byte[] byteAddress;

    /**
     * A {@link MacAddress} instance which represents an ethernet address.
     */
    private MacAddress macAddress;

    /**
     * Convert the given byte array that represents an ethernet address into
     * a long integer number.
     *
     * @param b  A byte array.
     * @return  A long integer number.
     * @throws NullPointerException
     *    {@code b} is {@code null}.
     * @throws IllegalArgumentException
     *    The length of {@code b} is not 6.
     */
    public static long toLong(byte[] b) {
        checkAddress(b);

        long num = 0L;
        int i = 0;
        do {
            num <<= Byte.SIZE;
            num |= b[i] & NumberUtils.MASK_BYTE;
            i++;
        } while (i < SIZE);

        return num;
    }

    /**
     * Convert a string representation of an ethernet address into a long
     * integer number.
     *
     * @param hex  A hex string which represents an ethernet address.
     * @return  A long integer number.
     * @throws NullPointerException
     *    {@code hex} is {@code null}.
     * @throws NumberFormatException
     *    The given string is not a hex string.
     * @throws IllegalArgumentException
     *    The given string is not a string representation of an ethernet
     *    address.
     */
    public static long toLong(String hex) {
        long value = 0L;
        int count = 1;
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < hex.length(); i++) {
            char c = hex.charAt(i);
            if (c == ByteUtils.HEX_SEPARATOR_CHAR) {
                count++;
                int octet = ByteUtils.parseHexOctet(builder.toString());
                value = (value << Byte.SIZE) | (long) octet;
                builder = new StringBuilder();
            } else {
                builder.append(c);
            }
        }

        if (count != SIZE) {
            throw new IllegalArgumentException("Too many octets: " + hex);
        }

        int octet = ByteUtils.parseHexOctet(builder.toString());
        return (value << Byte.SIZE) | (long) octet;
    }

    /**
     * Convert a long number which represents an ethernet address into a byte
     * array.
     *
     * @param addr  A long integer which represents an byte array.
     * @return  A byte array that contains 6 octets.
     */
    public static byte[] toBytes(long addr) {
        long value = addr;
        byte[] mac = new byte[SIZE];
        int i = SIZE - 1;
        do {
            mac[i] = (byte) value;
            value >>>= Byte.SIZE;
            i--;
        } while (i >= 0);

        return mac;
    }

    /**
     * Convert a string representation of an ethernet address into a byte
     * array.
     *
     * @param hex  A hex string which represents an ethernet address.
     * @return  A byte array that contains 6 octets if a valid hex string is
     *          passed. {@code null} is returned if {@code null} is passed.
     * @throws IllegalArgumentException
     *    The given string is not a string representation of an ethernet
     *    address.
     */
    public static byte[] toBytes(String hex) {
        byte[] bytes = ByteUtils.toBytes(hex);
        if (bytes != null) {
            checkAddress(bytes);
        }
        return bytes;
    }

    /**
     * Determine whether the given byte array represents a broadcast address
     * or not.
     *
     * @param bytes  A byte array to be tested.
     * @return  {@code true} only if the given byte array represents a
     *          broadcast address.
     */
    public static boolean isBroadcast(byte[] bytes) {
        return Arrays.equals(bytes, BROADCAST.getBytesImpl());
    }

    /**
     * Determine whether the given byte array represents an unicast address
     * or not.
     *
     * @param bytes  A byte array to be tested.
     * @return  {@code true} only if the given byte array represents an
     *          unicast address.
     */
    public static boolean isUnicast(byte[] bytes) {
        return (bytes.length == SIZE && (bytes[0] & BIT_MULTICAST) == 0);
    }

    /**
     * Create a new {@link EtherAddress} instance.
     *
     * @param bytes  A byte array which represents an ethernet address.
     * @return  An {@link EtherAddress} instance if {@code bytes} is not
     *          {@code null}. {@code null} if {@code bytes} is {@code null}.
     * @throws IllegalArgumentException
     *    The length of {@code bytes} is not 6.
     */
    public static EtherAddress create(byte[] bytes) {
        return (bytes == null) ? null : new EtherAddress(bytes);
    }

    /**
     * Create a new {@link EtherAddress} instance.
     *
     * @param hex  A hex string which represents an ethernet address.
     * @return  An {@link EtherAddress} instance if {@code hex} is not
     *          {@code null}. {@code null} if {@code hex} is {@code null}.
     * @throws IllegalArgumentException
     *    The given string is not a string representation of an ethernet
     *    address.
     */
    public static EtherAddress create(String hex) {
        return (hex == null) ? null : new EtherAddress(hex);
    }

    /**
     * Create a new {@link EtherAddress} instance.
     *
     * @param mac  A {@link MacAddress} instance.
     * @return  An {@link EtherAddress} instance if {@code mac} is not
     *          {@code null}. {@code null} if {@code mac} is {@code null}.
     * @throws IllegalArgumentException
     *    The given instance contains an invalid value.
     */
    public static EtherAddress create(MacAddress mac) {
        return (mac == null) ? null : new EtherAddress(mac);
    }

    /**
     * Create a new {@link EtherAddress} instance.
     *
     * @param mf  A {@link MacAddressFilter} instance.
     *            Note that MAC address mask is always ignored.
     * @return  An {@link EtherAddress} instance if a valid MAC address is
     *          configured in {@code mf}. Otherwise {@code null}.
     * @throws IllegalArgumentException
     *    The given instance contains an invalid value.
     */
    public static EtherAddress create(MacAddressFilter mf) {
        return (mf == null) ? null : create(mf.getAddress());
    }

    /**
     * Create a new {@link EtherAddress} instance.
     *
     * @param eaddr  An {@link EtherAddress} instance.
     * @return  An {@link EtherAddress} instance if {@code eaddr} is not
     *          {@code null}. {@code null} if {@code eaddr} is {@code null}.
     * @throws IllegalArgumentException
     *    The given instance contains an invalid value.
     */
    public static EtherAddress create(EthernetAddress eaddr) {
        return (eaddr == null) ? null : new EtherAddress(eaddr);
    }

    /**
     * Verify the given byte array which represents an ethernet address.
     *
     * @param b  A byte array to be tested.
     * @throws IllegalArgumentException
     *    The length of {@code b} is not 6.
     */
    private static void checkAddress(byte[] b) {
        if (b.length != SIZE) {
            throw new IllegalArgumentException("Invalid byte array length: " + b.length);
        }
    }

    /**
     * Private constructor used for JAXB mapping.
     */
    @SuppressWarnings("unused")
    private EtherAddress() {
    }

    /**
     * Construct a new instance.
     *
     * @param addr  A long integer value which represents an ethernet address.
     */
    public EtherAddress(long addr) {
        address = addr;
    }

    /**
     * Construct a new instance.
     *
     * @param bytes  A byte array which represents an ethernet address.
     * @throws NullPointerException
     *    {@code bytes} is {@code null}.
     * @throws IllegalArgumentException
     *    The length of {@code bytes} is not 6.
     */
    public EtherAddress(byte[] bytes) {
        byteAddress = bytes.clone();
        address = toLong(byteAddress);
    }

    /**
     * Construct a new instance.
     *
     * @param hex  A hex string which represents an ethernet address.
     * @throws NullPointerException
     *    {@code hex} is {@code null}.
     * @throws IllegalArgumentException
     *    The given string is not a string representation of an ethernet
     *    address.
     */
    public EtherAddress(String hex) {
        // Enforce lower case.
        String lhex = hex.toLowerCase(Locale.ENGLISH);
        macAddress = new MacAddress(lhex);
        address = toLong(lhex);
    }

    /**
     * Construct a new instance.
     *
     * @param mac  A {@link MacAddress} instance.
     * @throws NullPointerException
     *    {@code mac} is {@code null}.
     * @throws IllegalArgumentException
     *    The given instance contains an invalid value.
     */
    public EtherAddress(MacAddress mac) {
        // Enforce lower case.
        String hex = mac.getValue();
        String lhex = hex.toLowerCase(Locale.ENGLISH);
        if (hex.equals(lhex)) {
            macAddress = mac;
        } else {
            macAddress = new MacAddress(lhex);
        }
        address = toLong(lhex);
    }

    /**
     * Construct a new instance.
     *
     * @param eaddr  An {@link EtherAddress} instance.
     * @throws NullPointerException
     *    {@code eaddr} is {@code null}.
     * @throws IllegalArgumentException
     *    The given instance contains an invalid value.
     */
    public EtherAddress(EthernetAddress eaddr) {
        this(eaddr.getValue());
    }

    /**
     * Return a long number which represents this ethernet address.
     *
     * @return  A long number.
     */
    public long getAddress() {
        return address;
    }

    /**
     * Return a byte array which represents this ethernet address.
     *
     * @return  A byte array.
     */
    public byte[] getBytes() {
        return getBytesImpl().clone();
    }

    /**
     * Return a {@link MacAddress} instance which represents this ethernet
     * address.
     *
     * @return  A {@link MacAddress} instance.
     */
    public MacAddress getMacAddress() {
        MacAddress mac = macAddress;
        if (mac == null) {
            byte[] bytes = getBytesImpl();
            String hex = ByteUtils.toHexString(bytes);
            mac = new MacAddress(hex);
            macAddress = mac;
        }

        return mac;
    }

    /**
     * Return a {@link EtherAddress} instance which represents this ethernet
     * address.
     *
     * @return  A {@link EtherAddress} instance.
     */
    public EtherAddress getEthernetAddress() {
        // EtherAddress has a vulnerability that can corrupt internal byte
        // array. So we don't cache it.
        byte[] bytes = getBytesImpl();
        try {
            return new EtherAddress(bytes);
        } catch (Exception e) {
            // This should never happen.
            String msg = "Failed to create EtherAddress: " + getText();
            throw new IllegalStateException(msg, e);
        }
    }

    /**
     * Return a hex string which represents this ethernet address.
     *
     * <p>
     *   Note that below description of return value of this method is
     *   written for REST API document.
     * </p>
     *
     * @return
     *   A string representation of a MAC address.
     *
     *   <p>
     *     A MAC address is represented by hexadecimal notation with
     *     {@code ':'} inserted between octets.
     *     (e.g. {@code "11:22:33:aa:bb:cc"})
     *   </p>
     */
    @XmlValue
    public String getText() {
        return getMacAddress().getValue();
    }

    /**
     * Determine whether this instance represents a broadcast address or not.
     *
     * @return  {@code true} only if this instance represents a broadcast
     *          address.
     */
    public boolean isBroadcast() {
        return (address == BROADCAST.address);
    }

    /**
     * Determine whether this instance represents an unicast address or not.
     *
     * @return  {@code true} only if this instance represents an unicast
     *          address.
     */
    public boolean isUnicast() {
        return ((address & MASK_MULTICAST) == 0);
    }

    /**
     * Create a byte array that represents this ethernet address, and cache it
     * in this instance.
     *
     * @return  A byte array that represents this ethernet address.
     */
    private byte[] getBytesImpl() {
        byte[] bytes = byteAddress;
        if (bytes == null) {
            bytes = toBytes(address);
            byteAddress = bytes;
        }

        return bytes;
    }

    /**
     * Set a hex string which represents an ethernet address.
     *
     * <p>
     *   This method is called by JAXB.
     * </p>
     *
     * @param hex  A hex strin which represents an ethernet address.
     */
    @SuppressWarnings("unused")
    private void setText(String hex) {
        address = toLong(hex.trim());
    }

    // Object

    /**
     * Determine whether the given object is identical to this object.
     *
     * @param o  An object to be compared.
     * @return   {@code true} if identical. Otherwise {@code false}.
     */
    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (o == null || !getClass().equals(o.getClass())) {
            return false;
        }

        EtherAddress ea = (EtherAddress) o;
        return (address == ea.address);
    }

    /**
     * Return the hash code of this object.
     *
     * @return  The hash code.
     */
    @Override
    public int hashCode() {
        return NumberUtils.hashCode(address);
    }

    /**
     * Return a string representation of this object.
     *
     * @return  A string representation of this object.
     */
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder("EtherAddress[");
        return builder.append(getText()).append(']').toString();
    }
}