BUG-2825: add utility methods for instantiating DTOs
[mdsal.git] / model / ietf / ietf-type-util / src / main / java / org / opendaylight / mdsal / model / ietf / util / AbstractIetfYangUtil.java
1 /*
2  * Copyright (c) 2016 Pantheon Technologies s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.mdsal.model.ietf.util;
9
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Preconditions;
12 import javax.annotation.Nonnull;
13 import org.opendaylight.yangtools.yang.binding.util.StringValueObjectFactory;
14
15 /**
16  * Abstract utility class for dealing with MAC addresses as defined in the ietf-yang-types model. This class is
17  * used by revision-specific classes.
18  */
19 @Beta
20 public abstract class AbstractIetfYangUtil<T> {
21     private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
22     private final StringValueObjectFactory<T> factory;
23
24     protected AbstractIetfYangUtil(final Class<T> clazz) {
25         this.factory = StringValueObjectFactory.create(clazz, "00:00:00:00:00:00");
26     }
27
28     private static final void appendHexByte(final StringBuilder sb, final byte b) {
29         final int v = Byte.toUnsignedInt(b);
30         sb.append(HEX_CHARS[v >>> 4]);
31         sb.append(HEX_CHARS[v &  15]);
32     }
33
34     /**
35      * Make sure an array of characters does not include capital letters. This method assumes input conforms to
36      * MAC address format, e.g. it is composed of 6 groups of hexadecimal digits separated by colons. Behavior is
37      * undefined if the input does not meet this criteria.
38      *
39      * @param chars Input characters, may not be null
40      * @return True if the array has been modified
41      * @throws NullPointerException if input is null
42      */
43     private static boolean ensureLowerCase(@Nonnull final char[] chars) {
44         boolean ret = false;
45
46         for (int i = 0; i < chars.length; ++i) {
47             final char c = chars[i];
48             if (c >= 'A' && c <= 'F') {
49                 chars[i] = Character.toLowerCase(c);
50                 ret = true;
51             }
52         }
53
54         return ret;
55     }
56
57     /**
58      * Convert an array of 6 bytes into canonical MAC address representation, that is 6 groups of two hexadecimal
59      * lower-case digits each, separated by colons.
60      *
61      * @param bytes Input bytes, may not be null
62      * @return Canonical MAC address string
63      * @throws NullPointerException if input is null
64      * @throws IllegalArgumentException if length of input is not 6 bytes
65      */
66     @Nonnull private static String bytesToString(@Nonnull final byte[] bytes) {
67         Preconditions.checkArgument(bytes.length == 6, "MAC address should have 6 bytes, not %s", bytes.length);
68
69         final StringBuilder sb = new StringBuilder(17);
70         appendHexByte(sb, bytes[0]);
71         for (int i = 1; i < bytes.length; ++i) {
72             sb.append(':');
73             appendHexByte(sb, bytes[i]);
74         }
75
76         return sb.toString();
77     }
78
79     /**
80      * Convert the value of a MacAddress into the canonical representation.
81      *
82      * @param macAddress Input MAC address
83      * @return A MacAddress containing the canonical representation.
84      * @throws NullPointerException if macAddress is null
85      */
86     @Nonnull public final T canonizeMacAddress(@Nonnull final T macAddress) {
87         final char[] input = getValue(macAddress).toCharArray();
88         if (ensureLowerCase(input)) {
89             return factory.newInstance(input.toString());
90         } else {
91             return macAddress;
92         }
93     }
94
95     /**
96      * Create a MacAddress object holding the canonical representation of the 6 bytes
97      * passed in as argument.
98      * @param bytes 6-byte input array
99      * @return MacAddress with canonical string derived from input bytes
100      * @throws NullPointerException if bytes is null
101      * @throws IllegalArgumentException if length of input is not 6 bytes
102      */
103     @Nonnull public final T macAddressFor(@Nonnull final byte[] bytes) {
104         return factory.newInstance(bytesToString(bytes));
105     }
106
107     protected abstract String getValue(T macAddress);
108 }