Utilities (Media Authoring with Java API)
Date: 2016-02-05

tv.amwa.maj.util

## Class Utilities

- java.lang.Object
- - tv.amwa.maj.util.Utilities

-     public final class Utilities
      extends Object

  Static utilities shared by more than one class in the MAJ API and that may be of use more generally. Included here are methods to: calculate Modified Julian Dates, work out SMPTE timezone codes, convert timezone offsets, generate sort of unique host identifiers and for the truncation and extension of byte arrays.

- - ### Method Summary

    All Methods Static Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `static byte` | `byteFromCharacter(char c)` Convert a character representing a hexidecimal digit to the 4 least significant bits of a byte value of equivalent value.
    `static char[]` | `bytesToHexChars(byte[] bytes)` Convert binary data into a sequence of pairs of hexadecimal character values.
    `static byte[]` | `checkBytes(byte[] data, int requiredLength)` Ensures that an array contains exactly the required number of bytes.
    `static byte[]` | `compute7ByteTimeStamp(Calendar timeStamp)` Creates a 7 byte time stamp value suitable for use in the creation of unique identifiers.
    `static byte[]` | `createLocalHostID(int size)` Generates a byte array of the given size that should be a value unique to the host on which the current Java virtual machine is running.
    `static int` | `dmyToModifiedJulianDate(int day, int month, int year)` Converts a date represented as day, month and year values into a Modified Julian Date value.
    `static byte[]` | `getLocalHostID()` Generates an array of 6-bytes that is a fairly reliable identifier of the system on which this code is running.
    `static void` | `hexDump(ByteBuffer buffer)` Write a hexidecimal dump, with byte offsets and character conversions in the style of `hexdump -C`, to the standard output stream.
    `static byte[]` | `hexStringToBytes(String hexCharacters)` Convert a string of hex digits to a Java byte array, assuming that each pair of hex digits is the value of a byte in the array.
    `static int` | `hoursAndMinsToMilliseconds(int sign, int hours, int minutes)` Converts a number of hours, minutes and seconds and a corresponding sign value to an equivalent offset value from UTC (Universal Coordinated Time), measured in milliseconds.
    `static String` | `lowerFirstLetter(String camelString)` Create the Java field name of a property by lowering its first letter.
    `static String` | `makeSymbol(String name)` Create an XML-safe element name from the given name, converting any non-safe characters into underscore values "`_`".
    `static SecureRandom` | `seedRandomMaker()` Create and seed a secure random number generator.
    `static byte` | `timezoneCode(int timezoneOffset)` For a given offset from UTC measured in milliseconds, the timezone code defined in table 2 of SMPTE S309M-1999 is returned.
    `static byte` | `twoCharsToByte(char mostSignficantCharacter, char leastSignficantCharacter)` Create a byte value from its representation as two characters, one for the most significant 4 bits and one for the least significant 4 bits.

    - ### Methods inherited from class java.lang.Object

      `equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Method Detail

    - #### hoursAndMinsToMilliseconds

          public static final int hoursAndMinsToMilliseconds(int sign,
                                                             int hours,
                                                             int minutes)
                                                      throws IllegalArgumentException

      Converts a number of hours, minutes and seconds and a corresponding sign value to an equivalent offset value from UTC (Universal Coordinated Time), measured in milliseconds. Timezone offsets available by calling methods of the `Calendar` class are measured in milliseconds.

      Any sign value specified with the hours or minutes values are ignored and their magnitudes taken. Any positive value for the sign value, or zero, is taken to mean a positive offset from UTC, otherwise the value is considered a negative value offset from UTC. The maximum permitted offset from UTC is plus or minus 30 hours.

      Parameters:
        `sign` - Indicates a positive or negative offset from UTC.
        `hours` - Hours part of the magnitude of the offset from UTC.
        `minutes` - Minutes part of the magnitude of the offset from UTC.
      Returns:
        Offset from UTC represented in milliseconds.
      Throws:
        `IllegalArgumentException` - The magnitude of one or both of the hours or minutes value is outside the acceptable range.
      See Also:
        `Calendar.ZONE_OFFSET`, `Calendar.DST_OFFSET`

    - #### checkBytes

          public static final byte[] checkBytes(byte[] data,
                                                int requiredLength)
                                         throws NegativeArraySizeException

      Ensures that an array contains exactly the required number of bytes. If it does not, it is either padded with 0s to the right to make it up to the required length or truncated at the required length to make it fit.

      If the array passed in is `null`, an array of the required length containing 0's is created.

      Parameters:
        `data` - Array to check the length of.
        `requiredLength` - Required length of the array.
      Returns:
        If the length is OK, a cloned copy of the given array. Otherwise, a replacement array is created that is a padded or truncated version of the one provided to the required length.
      Throws:
        `NegativeArraySizeException` - The required array length is negative, which is not allowed for an array length.
      See Also:
        `PackageID`, `AUID`

    - #### seedRandomMaker

          public static final SecureRandom seedRandomMaker()

      Create and seed a secure random number generator. A number of different parameters that may be different system-to-system are combined with the current time in a mixing function to make a seed for the random number generator that is fairly difficult to guess.

      No warranty is provided with the use of this method. The data used as a seed may be publicly available, as is this code. This method should not be used as part of any application for: secure business-to-business transactions; digital rights management; customer relationship management; healthcare; ecommerce.

      Returns:
        Random number generator seeded in a reasonably secure way.
      See Also:
        `PackageID`, `AUID`, `Forge.randomAUID()`, `Forge.randomUMID()`

    - #### dmyToModifiedJulianDate

          public static final int dmyToModifiedJulianDate(int day,
                                                          int month,
                                                          int year)
                                                   throws IllegalArgumentException

      Converts a date represented as day, month and year values into a Modified Julian Date value. Modified Julian Dates are described on Wikipedia and the calculation of this method is based on the equations provided on the Wikipedia page.

      Parameters:
        `day` - Day part of the date to convert, in the range 1 to 31.
        `month` - Month part of the date to convert, in the range 1 to 12.
        `year` - Year part of the date convert, which must be 1754 A.D. or later to ensure no confusion exists with dates skipped in the UK in 1752, corrected in 1753.
      Returns:
        Date converted to a modified julian date representation.
      Throws:
        `IllegalArgumentException` - One or more of the arguments is outside the acceptable range.
      See Also:
        `compute7ByteTimeStamp(Calendar)`

    - #### timezoneCode

          public static final byte timezoneCode(int timezoneOffset)

      For a given offset from UTC measured in milliseconds, the timezone code defined in table 2 of SMPTE S309M-1999 is returned. If the given value does not match one defined in the table, a value of `0x39` is returned, the undefined value. The offset value must be accurate.

      Parameters:
        `timezoneOffset` - Timezone offset from UTC, measured in milliseconds.
      Returns:
        Timezone code corresponding to the given offset, or `0x39` if no directly corresponding code can be found for the given offset.
      See Also:
        `PackageID`

    - #### createLocalHostID

          public static final byte[] createLocalHostID(int size)
                                                throws NegativeArraySizeException

      Generates a byte array of the given size that should be a value unique to the host on which the current Java virtual machine is running. Java does not have an API call to access the unique hardware address of a system, so bytes compatible with an EUI-48 or EUI-64 locally administered value is generated.

      The four most significant bytes of the generated host id are set to be the four most significant bytes of the IP address of the current system. The least significant bits of the value are taken from the most local part of the domain name for the system. This is done with the intention that locally administered systems on separate private networks within different organisation should generate different ids.

      If no local network information is available, other local information about the identification of the machine is used instead. Note that this technique is likely to generate very similar or clashing host ids for systems configured with the same operating system, Java virtual machine and username.

      This method is no substitute for administering local system identities directly or using actual MAC addresses. The method should provide some degree of host id uniqueness within an organisation but should be used with caution if used as part of a public system or business-to-business applications. A much better approach is to pass the MAC address of a system in to a Java virtual machine as a system property, including a unique virtual machine id if the same system will be running more than one instance of an operating system in parallel.

      Parameters:
        `size` - Number of bytes or host id required. Values of 6 and 8 are recommended as the only values likely to produce reasonably reliable results.
      Returns:
        An array of bytes extracted from some relatively unique properties of the current system. Using this function on a set of systems on a network controlled by one organisation should produce unique results for each different system.
      Throws:
        `NegativeArraySizeException` - Cannot create a unique host ID value with a negative array size.
      See Also:
        `Forge.setLocalNodeID(byte[])`, `Forge.timebasedAUID()`, `Forge.generatePackageID(tv.amwa.maj.enumeration.MaterialType, tv.amwa.maj.record.InstanceNumberGeneration, tv.amwa.maj.record.MaterialNumberGeneration)`, `getLocalHostID()`

    - #### getLocalHostID

          public static final byte[] getLocalHostID()

      Generates an array of 6-bytes that is a fairly reliable identifier of the system on which this code is running. If the an Ethernet address of one of the network interfaces of this system is available, this is returned. Otherwise, the `createLocalHostID(int)` method is called to generate a value based on domain name and IP address.

      The value returned is designed to be good enough for time-based UUID generation within a specific facility or well controlled environment. For rigorous control, a system administrator should use `Forge.setLocalNodeID(byte[])` to inject values known to be totally unique.

      Returns:
        Fairly good unique identifier for this system.
      See Also:
        `Forge.setLocalNodeID(byte[])`, `Forge.timebasedAUID()`, `Forge.generatePackageID(tv.amwa.maj.enumeration.MaterialType, tv.amwa.maj.record.InstanceNumberGeneration, tv.amwa.maj.record.MaterialNumberGeneration)`, `createLocalHostID(int)`

    - #### compute7ByteTimeStamp

          public static final byte[] compute7ByteTimeStamp(Calendar timeStamp)
                                                    throws NullPointerException

      Creates a 7 byte time stamp value suitable for use in the creation of unique identifiers. The value generated uses the time stamp accessed through the given `Calendar` value, in combination with a local counter, to create 7 bytes representing the time stamp.

      Making 24 consecutive thread-safe calls to this method with the same calendar value will result in 24 different byte arrays. Java only provides time resolution down to the nearest millisecond and so multiple calls to this method on a fast system using the current system time would result in the same value unless a local counter is used. However, many modern systems are more than capable of calling this method more than 24 times each millisecond so it is recommended that any identifier generated using this method is combined with the output a random number generator to achieve a satisfactory degree of uniqueness.

      The value returned is found from a clock cycle through the day combined with a Modified Julian Date (MJD), as follows:

      - bytes 0 to 3 - An unsigned integer in network byte order representing a clock cycle value ranging from 0 at the start of a day to 2073599999 at the end.
      - byte 4 - Top nibble (4 most significant bits) are the units of the MJD and bottom nibble the tens of the MJD.
      - byte 5 - Top nibble is the 100s of the MJD, bottom nibble is the 1000s.
      - byte 6 - Top nibble is the 10000s of the MJD, bottom nibble is the 100000s.

      For example, to generate a 7-byte timestamp for right now, call:

      `compute7ByteTimeStamp(Calendar.getInstance());`
      Parameters:
        `timeStamp` - Java calendar value to use to generate a time stamp with.
      Returns:
        7-byte timestamp made from a daily clock cycle and Modified Julian Date computed from the given time stamp.
      Throws:
        `NullPointerException` - Cannot create a 7-byte timestamp with a `null` value.
      See Also:
        `dmyToModifiedJulianDate(int, int, int)`, `PackageID`

    - #### bytesToHexChars

          public static final char[] bytesToHexChars(byte[] bytes)
                                              throws NullPointerException

      Convert binary data into a sequence of pairs of hexadecimal character values.

      Parameters:
        `bytes` - Bytes to convert to a hex string.
      Returns:
        Hex string representation of the given bytes.
      Throws:
        `NullPointerException` - The given array of bytes is `null`.
      See Also:
        `hexStringToBytes(String)`

    - #### hexStringToBytes

          public static final byte[] hexStringToBytes(String hexCharacters)
                                               throws NullPointerException,
                                                      IndexOutOfBoundsException

      Convert a string of hex digits to a Java byte array, assuming that each pair of hex digits is the value of a byte in the array. The byte array will be halg the length of the given string.

      For example, `010A10` is converted into `{ (byte) 1, (byte) 10, (byte) 16 }`.

      Parameters:
        `hexCharacters` - Hexadecimal characters to convert to a byte array.
      Returns:
        Byte array created from the given hexadecimal digits.
      Throws:
        `NullPointerException` - The given string of hex digits is `null`.
        `IndexOutOfBoundsException` - The length of the given string of hexadecimal digits is not a multiple of 2.
      See Also:
        `bytesToHexChars(byte[])`

    - #### lowerFirstLetter

          public static final String lowerFirstLetter(String camelString)

      Create the Java field name of a property by lowering its first letter. This method is useful for classes that defining their own object relational mappings. For example, a property called CreationTime is represented in the MAJ API with a private field called creationTime.

      Parameters:
        `camelString` - String in camel case.
      Returns:
        Same string but with the first character converted to lower case.

    - #### twoCharsToByte

          public static final byte twoCharsToByte(char mostSignficantCharacter,
                                                  char leastSignficantCharacter)
                                           throws NumberFormatException

      Create a byte value from its representation as two characters, one for the most significant 4 bits and one for the least significant 4 bits.

      Parameters:
        `mostSignficantCharacter` - Hexidecimal character representing the 4 most significant bits of a byte value.
        `leastSignficantCharacter` - Hexidecimal character representing the 4 least significant bits of a byte value.
      Returns:
        Byte representation of the two hexidecimal characters.
      Throws:
        `NumberFormatException` - One or both of the characters is/are not hexidecimal characters.

    - #### byteFromCharacter

          public static final byte byteFromCharacter(char c)
                                              throws NumberFormatException

      Convert a character representing a hexidecimal digit to the 4 least significant bits of a byte value of equivalent value. This method accepts both upper and lower case hexidecimal digits.

      Parameters:
        `c` - Hexidecimal character to convert.
      Returns:
        Equivalent byte value to the given hexidecimal digit.
      Throws:
        `NumberFormatException` - The given character is not a hexidecimal digit.

    - #### hexDump

          public static final void hexDump(ByteBuffer buffer)
                                    throws NullPointerException

      Write a hexidecimal dump, with byte offsets and character conversions in the style of `hexdump -C`, to the standard output stream. The buffer is dumped from its current position to its limit. The buffer is rewound to the initial position.

      Parameters:
        `buffer` - Buffer to dump to the output stream.
      Throws:
        `NullPointerException` - Cannot dump a `null` buffer.

    - #### makeSymbol

          public static final String makeSymbol(String name)
                                         throws NullPointerException,
                                                IllegalArgumentException

      Create an XML-safe element name from the given name, converting any non-safe characters into underscore values "`_`". For `null` or empty values, a `null` is returned as these are not legal symbols.

      Parameters:
        `name` - Name to convert to a symbol.
      Returns:
        Symbol created from the name that is safe to use as an XML element name.
      Throws:
        `NullPointerException` - Cannot convert a null name into a safe symbol value.
        `IllegalArgumentException` - Cannot convert an empty string into a safe symbol value.
      See Also:
        `MetaDefinition.getSymbol()`

(c)2007-2016 Richard Cartwright, all rights reserved. Licensed under Apache 2 license and subject to the AMWA IPR policy.