2 * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.model.ietf.util;
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Preconditions;
12 import java.util.Arrays;
13 import javax.annotation.Nonnull;
14 import org.opendaylight.yangtools.yang.binding.util.StringValueObjectFactory;
17 * Abstract utility class for dealing with MAC addresses as defined in the ietf-yang-types model. This class is
18 * used by revision-specific classes.
21 public abstract class AbstractIetfYangUtil<T> {
22 private static final int MAC_BYTE_LENGTH = 6;
23 private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
24 private static final byte[] HEX_VALUES;
26 final byte[] b = new byte['f' + 1];
27 Arrays.fill(b, (byte)-1);
29 for (char c = '0'; c <= '9'; ++c) {
30 b[c] = (byte)(c - '0');
32 for (char c = 'A'; c <= 'F'; ++c) {
33 b[c] = (byte)(c - 'A' + 10);
35 for (char c = 'a'; c <= 'f'; ++c) {
36 b[c] = (byte)(c - 'a' + 10);
42 private final StringValueObjectFactory<T> factory;
44 protected AbstractIetfYangUtil(final Class<T> clazz) {
45 this.factory = StringValueObjectFactory.create(clazz, "00:00:00:00:00:00");
48 private static final void appendHexByte(final StringBuilder sb, final byte b) {
49 final int v = Byte.toUnsignedInt(b);
50 sb.append(HEX_CHARS[v >>> 4]);
51 sb.append(HEX_CHARS[v & 15]);
55 * Make sure an array of characters does not include capital letters. This method assumes input conforms to
56 * MAC address format, e.g. it is composed of 6 groups of hexadecimal digits separated by colons. Behavior is
57 * undefined if the input does not meet this criteria.
59 * @param chars Input characters, may not be null
60 * @return True if the array has been modified
61 * @throws NullPointerException if input is null
63 private static boolean ensureLowerCase(@Nonnull final char[] chars) {
66 for (int i = 0; i < chars.length; ++i) {
67 final char c = chars[i];
68 if (c >= 'A' && c <= 'F') {
69 chars[i] = Character.toLowerCase(c);
78 * Convert an array of 6 bytes into canonical MAC address representation, that is 6 groups of two hexadecimal
79 * lower-case digits each, separated by colons.
81 * @param bytes Input bytes, may not be null
82 * @return Canonical MAC address string
83 * @throws NullPointerException if input is null
84 * @throws IllegalArgumentException if length of input is not 6 bytes
86 @Nonnull private static String bytesToString(@Nonnull final byte[] bytes) {
87 Preconditions.checkArgument(bytes.length == MAC_BYTE_LENGTH, "MAC address should have 6 bytes, not %s",
90 final StringBuilder sb = new StringBuilder(17);
91 appendHexByte(sb, bytes[0]);
92 for (int i = 1; i < MAC_BYTE_LENGTH; ++i) {
94 appendHexByte(sb, bytes[i]);
101 * Convert the value of a MacAddress into the canonical representation.
103 * @param macAddress Input MAC address
104 * @return A MacAddress containing the canonical representation.
105 * @throws NullPointerException if macAddress is null
107 @Nonnull public final T canonizeMacAddress(@Nonnull final T macAddress) {
108 final char[] input = getValue(macAddress).toCharArray();
109 if (ensureLowerCase(input)) {
110 return factory.newInstance(input.toString());
117 * Create a MacAddress object holding the canonical representation of the 6 bytes
118 * passed in as argument.
119 * @param bytes 6-byte input array
120 * @return MacAddress with canonical string derived from input bytes
121 * @throws NullPointerException if bytes is null
122 * @throws IllegalArgumentException if length of input is not 6 bytes
124 @Nonnull public final T macAddressFor(@Nonnull final byte[] bytes) {
125 return factory.newInstance(bytesToString(bytes));
128 private static byte hexValue(final char c) {
131 // Performance optimization: access the array and rely on the VM for catching
132 // illegal access (which boils down to illegal character, which should never happen.
134 } catch (IndexOutOfBoundsException e) {
139 throw new IllegalArgumentException("Invalid character '" + c + "' encountered");
145 @Nonnull public final byte[] bytesFor(@Nonnull final T macAddress) {
146 final String mac = getValue(macAddress);
147 final byte[] ret = new byte[MAC_BYTE_LENGTH];
149 for (int i = 0, base = 0; i < MAC_BYTE_LENGTH; ++i, base += 3) {
150 ret[i] = (byte) ((hexValue(mac.charAt(base)) << 4) | hexValue(mac.charAt(base + 1)));
156 protected abstract String getValue(T macAddress);