Add HexString/DottedQuad/Uuid support to IetfYangUtil
[mdsal.git] / model / ietf / ietf-type-util / src / main / java / org / opendaylight / mdsal / model / ietf / util / AbstractIetfYangUtil.java
index e9c6f33433313c4aea4d317d8998b659d1c5e875..86fa3a4efe745683e59844d46ed0974b5cfe93b1 100644 (file)
@@ -11,7 +11,8 @@ import static com.google.common.base.Preconditions.checkArgument;
 
 import com.google.common.annotations.Beta;
 import java.util.Arrays;
-import javax.annotation.Nonnull;
+import java.util.UUID;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.spec.reflect.StringValueObjectFactory;
 
 /**
@@ -22,10 +23,12 @@ import org.opendaylight.mdsal.binding.spec.reflect.StringValueObjectFactory;
  * @param <P> phys-address type
  */
 @Beta
-public abstract class AbstractIetfYangUtil<M, P> {
+public abstract class AbstractIetfYangUtil<M, P, H, Q, U> {
     private static final int MAC_BYTE_LENGTH = 6;
     private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
-    private static final byte[] HEX_VALUES;
+    private static final byte @NonNull[] EMPTY_BYTES = new byte[0];
+    private static final byte @NonNull[] HEX_VALUES;
+
     static {
         final byte[] b = new byte['f' + 1];
         Arrays.fill(b, (byte)-1);
@@ -45,13 +48,19 @@ public abstract class AbstractIetfYangUtil<M, P> {
 
     private final StringValueObjectFactory<M> macFactory;
     private final StringValueObjectFactory<P> physFactory;
+    private final StringValueObjectFactory<H> hexFactory;
+    private final StringValueObjectFactory<Q> quadFactory;
+    private final StringValueObjectFactory<U> uuidFactory;
 
-    protected AbstractIetfYangUtil(final Class<M> macClass, final Class<P> physClass) {
+    protected AbstractIetfYangUtil(final Class<M> macClass, final Class<P> physClass, final Class<H> hexClass,
+            final Class<Q> quadClass, final Class<U> uuidClass) {
         this.macFactory = StringValueObjectFactory.create(macClass, "00:00:00:00:00:00");
         this.physFactory = StringValueObjectFactory.create(physClass, "00:00");
+        this.hexFactory = StringValueObjectFactory.create(hexClass, "00");
+        this.quadFactory = StringValueObjectFactory.create(quadClass, "0.0.0.0");
+        this.uuidFactory = StringValueObjectFactory.create(uuidClass, "f81d4fae-7dec-11d0-a765-00a0c91e6bf6");
     }
 
-
     /**
      * Convert the value of a MacAddress into the canonical representation.
      *
@@ -59,7 +68,7 @@ public abstract class AbstractIetfYangUtil<M, P> {
      * @return A MacAddress containing the canonical representation.
      * @throws NullPointerException if macAddress is null
      */
-    @Nonnull public final M canonizeMacAddress(@Nonnull final M macAddress) {
+    public final @NonNull M canonizeMacAddress(final @NonNull M macAddress) {
         final char[] input = getValue(macAddress).toCharArray();
         return ensureLowerCase(input) ? macFactory.newInstance(String.valueOf(input)) : macAddress;
     }
@@ -72,12 +81,16 @@ public abstract class AbstractIetfYangUtil<M, P> {
      * @throws NullPointerException if bytes is null
      * @throws IllegalArgumentException if length of input is not 6 bytes
      */
-    @Nonnull public final M macAddressFor(@Nonnull final byte[] bytes) {
+    public final @NonNull M macAddressFor(final byte @NonNull[] bytes) {
         checkArgument(bytes.length == MAC_BYTE_LENGTH, "MAC address should have 6 bytes, not %s",
                 bytes.length);
         return macFactory.newInstance(bytesToString(bytes, 17));
     }
 
+    public final byte @NonNull[] macAddressBytes(final @NonNull M macAddress) {
+        return stringToBytes(getValue(macAddress), MAC_BYTE_LENGTH);
+    }
+
     /**
      * Convert the value of a PhysAddress into the canonical representation.
      *
@@ -85,7 +98,7 @@ public abstract class AbstractIetfYangUtil<M, P> {
      * @return A PhysAddress containing the canonical representation.
      * @throws NullPointerException if physAddress is null
      */
-    @Nonnull public final P canonizePhysAddress(@Nonnull final P physAddress) {
+    public final @NonNull P canonizePhysAddress(final @NonNull P physAddress) {
         final char[] input = getPhysValue(physAddress).toCharArray();
         return ensureLowerCase(input) ? physFactory.newInstance(String.valueOf(input)) : physAddress;
     }
@@ -98,41 +111,70 @@ public abstract class AbstractIetfYangUtil<M, P> {
      * @throws NullPointerException if bytes is null
      * @throws IllegalArgumentException if length of input is not at least 1 byte
      */
-    @Nonnull public final P physAddressFor(@Nonnull final byte[] bytes) {
+    public final @NonNull P physAddressFor(final byte @NonNull[] bytes) {
         checkArgument(bytes.length > 0, "Physical address should have at least one byte");
-        return physFactory.newInstance(bytesToString(bytes, (bytes.length + 1) / 3));
+        return physFactory.newInstance(bytesToString(bytes, bytes.length * 3 - 1));
     }
 
-    @Nonnull public final byte[] bytesFor(@Nonnull final M macAddress) {
-        final String mac = getValue(macAddress);
-        final byte[] ret = new byte[MAC_BYTE_LENGTH];
+    public final byte @NonNull[] physAddressBytes(final @NonNull P physAddress) {
+        final String str = getPhysValue(physAddress);
+        return str.isEmpty() ? EMPTY_BYTES : stringToBytes(str, str.length() / 3 + 1);
+    }
 
-        for (int i = 0, base = 0; i < MAC_BYTE_LENGTH; ++i, base += 3) {
-            ret[i] = (byte) (hexValue(mac.charAt(base)) << 4 | hexValue(mac.charAt(base + 1)));
-        }
+    @Deprecated
+    public final byte @NonNull[] bytesFor(final @NonNull M macAddress) {
+        return macAddressBytes(macAddress);
+    }
 
-        return ret;
+    public final @NonNull H hexStringFor(final byte @NonNull[] bytes) {
+        checkArgument(bytes.length > 0, "Hex string should have at least one byte");
+        return hexFactory.newInstance(bytesToString(bytes, bytes.length * 3 - 1));
+    }
+
+    public final byte @NonNull[] hexStringBytes(final @NonNull H hexString) {
+        final String str = getHexValue(hexString);
+        return stringToBytes(str, str.length() / 3 + 1);
+    }
+
+    public final @NonNull Q dottedQuadFor(final byte @NonNull[] bytes) {
+        checkArgument(bytes.length == 4, "Dotted-quad should have 4 bytes");
+        return quadFactory.newInstance(AbstractIetfInetUtil.addressStringV4(bytes));
+    }
+
+    public final byte @NonNull[] dottedQuadBytes(final @NonNull Q hexString) {
+        final String str = getQuadValue(hexString);
+        final byte[] bytes = new byte[4];
+        Ipv4Utils.fillIpv4Bytes(bytes, 0, str, 0, str.length());
+        return bytes;
+    }
+
+    public final @NonNull U uuidFor(final @NonNull UUID uuid) {
+        return uuidFactory.newInstance(uuid.toString());
     }
 
     protected abstract String getValue(M macAddress);
 
     protected abstract String getPhysValue(P physAddress);
 
-    static byte hexValue(final char c) {
-        byte v;
+    protected abstract String getHexValue(H hexString);
+
+    protected abstract String getQuadValue(Q dottedQuad);
+
+    static byte hexValue(final char ch) {
+        byte value;
         try {
             // Performance optimization: access the array and rely on the VM for catching
             // illegal access (which boils down to illegal character, which should never happen.
-            v = HEX_VALUES[c];
+            value = HEX_VALUES[ch];
         } catch (IndexOutOfBoundsException e) {
-            v = -1;
+            value = -1;
         }
 
-        if (v < 0) {
-            throw new IllegalArgumentException("Invalid character '" + c + "' encountered");
+        if (value < 0) {
+            throw new IllegalArgumentException("Invalid character '" + ch + "' encountered");
         }
 
-        return v;
+        return value;
     }
 
     /**
@@ -144,7 +186,7 @@ public abstract class AbstractIetfYangUtil<M, P> {
      * @return True if the array has been modified
      * @throws NullPointerException if input is null
      */
-    private static boolean ensureLowerCase(@Nonnull final char[] chars) {
+    private static boolean ensureLowerCase(final char @NonNull[] chars) {
         boolean ret = false;
 
         for (int i = 0; i < chars.length; ++i) {
@@ -168,7 +210,7 @@ public abstract class AbstractIetfYangUtil<M, P> {
      * @throws NullPointerException if input is null
      * @throws IllegalArgumentException if length of input is not 6 bytes
      */
-    @Nonnull private static String bytesToString(@Nonnull final byte[] bytes, final int charHint) {
+    private static @NonNull String bytesToString(final byte @NonNull[] bytes, final int charHint) {
         final StringBuilder sb = new StringBuilder(charHint);
         appendHexByte(sb, bytes[0]);
         for (int i = 1; i < bytes.length; ++i) {
@@ -178,8 +220,16 @@ public abstract class AbstractIetfYangUtil<M, P> {
         return sb.toString();
     }
 
-    private static final void appendHexByte(final StringBuilder sb, final byte b) {
-        final int v = Byte.toUnsignedInt(b);
-        sb.append(HEX_CHARS[v >>> 4]).append(HEX_CHARS[v & 15]);
+    private static void appendHexByte(final StringBuilder sb, final byte byteVal) {
+        final int intVal = Byte.toUnsignedInt(byteVal);
+        sb.append(HEX_CHARS[intVal >>> 4]).append(HEX_CHARS[intVal & 15]);
+    }
+
+    private static byte @NonNull[] stringToBytes(final String str, final int length) {
+        final byte[] ret = new byte[length];
+        for (int i = 0, base = 0; i < length; ++i, base += 3) {
+            ret[i] = (byte) (hexValue(str.charAt(base)) << 4 | hexValue(str.charAt(base + 1)));
+        }
+        return ret;
     }
 }