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

tv.amwa.maj.io.xml

## Class LocalHandler

- java.lang.Object
- - tv.amwa.maj.io.xml.MasterContentHandler
  - - tv.amwa.maj.io.xml.LocalHandler

- All Implemented Interfaces:
    ContentHandler, AAFSpecifiedClasses
  Direct Known Subclasses:
    ProductVersionImpl.XMLHandler, RGBAComponentImpl.XMLHandler

      public abstract class LocalHandler
      extends MasterContentHandler
      implements ContentHandler

  Content handler class that is implemented by all content handlers that can deserialize an XML element and create an object. This abstract class provides implementations for all of the `ContentHandler` interfaces, requiring the implementor of a handler for a specific element type to override the abstract `createResult()` method. Subclasses of this class can be registered as element content handlers using the `MasterContentHandler.registerHandler(Class)` method.

  The following example code shows how an element specific content handler could be implemented:

       public static class MyObjectHandler
           extends LocalHandler
           implements ContentHandler {

           public final static String elementName = "MyElement";
           public final static String[] dataElementNames = new String[] {
                   "DataElement1", "DataElement2" };
           public final static String[] subElementNames = new String[] {
                   "SubElement1", "SubElement2" };

           protected Object createResult()
               throws SAXException {

               return new MyObject(
                   getAttributes().get("myAttribute"),
                   getElementData("DataElement1"),
                   Integer.parseInt(getAttributeValue("DataElement1", "dataAttribute1")),
                   (MySubObject1) getSubElement("SubElement1"),
                   Integer.parseInt(getElementData("DataElement2")),
                   (MySubObject2) getSubElement("SubElement2"));
           }
       }

  The above code would successfully parse the following fragment of XML and create an instance of `MyObject`.

       <?xml version="1.0" encoding="UTF-8"?>
       <!--Throw away comment-->
       <MyElement myAttribute="my attribute value">
         <DataElement1 dataAttribute1="7">data element 1 test value</DataElement1>
         <DataElement2>67</DataElement>
         <SubElement1>
           <ChildValue>I'm a child</ChildValue>
         </SubElement1>
         <SubElement2 subElement2Attribute="0x6f"/>
       </MyElement>

  The rules surrounding the implementation of a content handler that extends this class are as follows:

  - Content handlers must provide the element name they process as the value of a `public final static String` value called "`elementName`". This is extracted from the handler by the parser and if any elements of this name are encountered during a parse, the handler associated with this element name will be called.
  - Any child elements of the element associated with the content handler that do not themselves contain sub elements, only attributes and/or text content, are known as data elements. Content handlers must provide a list of the names of all data elements that can be expected to be encountered on a parse of the associated element's content, whether they are required or optional. This list should be a `public final static String[]`. If the list is empty or not present, the element associated with the content handler will be assumed to have no child data elements and if one is encountered, a `SAXException` will be thrown.
  - Any child elements of the element associated with the content handler that themselves contain child elements as content are known as sub elements. Content handlers must provide a list of the names of all sub elements that can expected to be encountered on a parse of the associated element's content, whether they are required or optional. This list should be a `public final static String[]`. If the list is empty or not present, the element associated with the content handler will be assumed to have not sub elements and if one is encountered, a `SAXException` will be thrown. The sub elements will be parsed with their own content handler, which must have been registered. If more than one of the same sub element is found, the values are appended to a list of content.
  - The handler must provide an implementation of the `createResult()` method that creates an instance of the deserialized XML fragment. This method is called after all available data elements and sub elements have been parsed and their values are available through calls to the `getElementData(String)` for data elements, `getSubElement(String)` for a sub element, `getSubElementList(String)` for lists of sub elements of the same type and `getAttributesForElement(String)` for attributes of data elements or sub elements. All of these methods could return `null` if the requested value is not available and implementations of the `createResult()` method must be coded to expect this, throwing an `Exception` if creation of a result was not possible.

  This content handler hierarchy has been designed to make it easy to extend the core objects available in this AAF implementation to other classes while providing an efficient event-driven XML parser.

- - ### Field Summary

    - ### Fields inherited from interface tv.amwa.maj.industry.AAFSpecifiedClasses

      `abstractInterchangeable, abstractMeta, existingMeta, interchangeable, meta`

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `LocalHandler()`

  - ### Method Summary

    All Methods Instance Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `boolean` | `areAttributesPresent(String elementName)` Check if attributes are available for the given element name.
    `void` | `characters(char[] ch, int start, int length)`
    `void` | `endDocument()` Called if the end of a document is reached within a local handler, which indicates an exceptional condition as only master content handlers should manage document ends.
    `void` | `endElement(String uri, String localName, String name)` Called at the end of any child data element of the element associated with this local handler or at the end of the element itself.
    `Map<String,String>` | `getAttributesForElement(String elementName)` Returns the attributes of a child data element or child sub element, or `null` if the element name does not match a known element name and/or no attribute values are available for that element.
    `String` | `getAttributeValueChildElement(String elementName, String attributeName)` Returns the value of an attribute of a child data element or child sub element, or `null` if the element or the attribute is not known.
    `byte[]` | `getBytesFromStream(String streamName)` Find a named stream of data attached to the parent content handler, read it and return it as a byte array.
    `String` | `getElementData(String elementName)` Returns the text content of a child data element of the given name, or `null` if the data element was not present or if the name does not match a known data element name.
    `List<String>` | `getElementDataList(String elementName)`
    `InputStream` | `getInputStreamForName(String streamName)` Return the input stream with the given name from the collection of streams that has been attached to this content handler.
    `Object` | `getSubElement(String elementName)` Returns the result object created after the deserialization of a sub element of the given element name, or `null` if the sub element name does not match the name of a known sub element or a result is not available.
    `List<Object>` | `getSubElementList(String elementName)` Returns a list of result objects created after the deserialization of child sub elements with the given element name in the order in which they were declared in the XML file.
    `boolean` | `isDataElementList(String elementName)` Returns `true` if the given data element name is definately linked with a list of values, which is the case if more than one has been encountered.
    `boolean` | `isDataElementPresent(String elementName)` Check if text content is available for a child data element of the given name.
    `boolean` | `isSingleDataElement(String elementName)` Returns `true` if exactly one value for a data element value matching the given element name is available within this local handler.
    `boolean` | `isSingleSubElement(String elementName)` Returns `true` if exactly one deserialized sub element value matching the given element name is available within this local handler.
    `boolean` | `isSubElementList(String elementName)` Returns `true` if the given sub element name is definately linked with a list of values, which is the case if more than one has been encountered.
    `boolean` | `isSubElementPresent(String elementName)` Check if a deserialized sub element value or values is/are available for the given sub element name.
    `void` | `startElement(String uri, String localName, String name, Attributes atts)` Called at the start of any data element or sub element.

    - ### Methods inherited from class tv.amwa.maj.io.xml.MasterContentHandler

      `endPrefixMapping, getAttributesForThis, getAttributeValueThisElement, getElementName, getFullElementName, getNamespace, ignorableWhitespace, processingInstruction, registerCoreHandlers, registerHandler, registerHandlersForClass, setDocumentLocator, skippedEntity, startDocument, startPrefixMapping`

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

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

    - ### Methods inherited from interface org.xml.sax.ContentHandler

      `endPrefixMapping, ignorableWhitespace, processingInstruction, setDocumentLocator, skippedEntity, startDocument, startPrefixMapping`

- - ### Constructor Detail

    - #### LocalHandler

          public LocalHandler()

  - ### Method Detail

    - #### characters

          public void characters(char[] ch,
                                 int start,
                                 int length)
                          throws SAXException

      Specified by:
        `characters` in interface `ContentHandler`
      Overrides:
        `characters` in class `MasterContentHandler`
      Throws:
        `SAXException`
      See Also:
        `MasterContentHandler.characters(char[], int, int)`

    - #### endDocument

          public final void endDocument()
                                 throws SAXException

      Called if the end of a document is reached within a local handler, which indicates an exceptional condition as only master content handlers should manage document ends. This method always throws a `SAXException`.

      Specified by:
        `endDocument` in interface `ContentHandler`
      Overrides:
        `endDocument` in class `MasterContentHandler`
      Throws:
        `SAXException`
      See Also:
        `MasterContentHandler.endDocument()`

    - #### endElement

          public final void endElement(String uri,
                                       String localName,
                                       String name)
                                throws SAXException

      Called at the end of any child data element of the element associated with this local handler or at the end of the element itself. If the call is at the end of the element itself, the content handler is set back to the `MasterContentHandler.parentHandler` and the handler generates its result.

      Specified by:
        `endElement` in interface `ContentHandler`
      Overrides:
        `endElement` in class `MasterContentHandler`
      Throws:
        `SAXException`
      See Also:
        `MasterContentHandler.endElement(java.lang.String, java.lang.String, java.lang.String)`

    - #### startElement

          public final void startElement(String uri,
                                         String localName,
                                         String name,
                                         Attributes atts)
                                  throws SAXException

      Called at the start of any data element or sub element. For data elements, this method prepares to capture any character data that might be available. For sub elements, this method finds and instantiates an appropriate content handler.

      Specified by:
        `startElement` in interface `ContentHandler`
      Overrides:
        `startElement` in class `MasterContentHandler`
      Throws:
        `SAXException`
      See Also:
        `MasterContentHandler.startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)`

    - #### getElementData

          public final String getElementData(String elementName)
                                      throws NullPointerException

      Returns the text content of a child data element of the given name, or `null` if the data element was not present or if the name does not match a known data element name.

      Parameters:
        `elementName` - Name of the data element to retrieve the content of.
      Returns:
        Text content of the data element with the given name, or `null` if associated text content is not available.
      Throws:
        `NullPointerException` - The element name argument is `null`.

    - #### getElementDataList

          public final List<String> getElementDataList(String elementName)

    - #### getAttributesForElement

          public final Map<String,String> getAttributesForElement(String elementName)
                                                           throws NullPointerException

      Returns the attributes of a child data element or child sub element, or `null` if the element name does not match a known element name and/or no attribute values are available for that element.

      Parameters:
        `elementName` - Name of the element to retrieve the attributes of.
      Returns:
        Attributes of the data element with the given name, or `null` if an associated mao of attribute values is not available.
      Throws:
        `NullPointerException` - The element name argument is `null`.

    - #### getAttributeValueChildElement

          public final String getAttributeValueChildElement(String elementName,
                                                            String attributeName)
                                                     throws NullPointerException

      Returns the value of an attribute of a child data element or child sub element, or `null` if the element or the attribute is not known.

      Parameters:
        `elementName` - Name of the element to retrieve an attribute value from.
        `attributeName` - Name of the attribute to retrieve the value of.
      Returns:
        Value of the attribute from the child element of the given name and the given attribute name, or `null` if an appropriate attribute value cannot be found.
      Throws:
        `NullPointerException`

    - #### getSubElement

          public final Object getSubElement(String elementName)
                                     throws NullPointerException

      Returns the result object created after the deserialization of a sub element of the given element name, or `null` if the sub element name does not match the name of a known sub element or a result is not available. If the sub element occurred more than once in an XML element, this method will return the first one encountered. Use `isSingleSubElement(String)` to establish if this is the only value with this sub element name that has been encountered.

      Parameters:
        `elementName` - Name of the sub element to retrieve the deserialized value of.
      Returns:
        Deserialized version of the sub element with the given element name, or `null` if an associated deserialized value is not available.
      Throws:
        `NullPointerException` - The element name argument is `null`.

    - #### getSubElementList

          public final List<Object> getSubElementList(String elementName)
                                               throws NullPointerException

      Returns a list of result objects created after the deserialization of child sub elements with the given element name in the order in which they were declared in the XML file. This method returns `null` if the sub element name does not match the name of a known sub element or a result is not available. Use the `isSubElementList(String)` to find out if a list of sub element values definitely exists for a particular sub element name.

      Parameters:
        `elementName` - Name of the sub element to retrieve the list of deserialized values for.
      Returns:
        List of deserialized values from element names matching the given name.
      Throws:
        `NullPointerException` - The element name argument is `null`.

    - #### isSubElementList

          public final boolean isSubElementList(String elementName)
                                         throws NullPointerException

      Returns `true` if the given sub element name is definately linked with a list of values, which is the case if more than one has been encountered. If only one was encountered, the sub element name could correspond to a list or a single value. This parser does not have access to a DTD or schema to check and so it is up to the caller to decide whether a list containing a single value represents a list of sub elements or a single sub element.

      Parameters:
        `elementName` - Sub element name to check if more than one value with that element name has been deserialized.
      Returns:
        Does the given sub element name correspond to more than one deserialized value in this local handler?
      Throws:
        `NullPointerException` - The element name argument is `null`.

    - #### isDataElementList

          public final boolean isDataElementList(String elementName)
                                          throws NullPointerException

      Returns `true` if the given data element name is definately linked with a list of values, which is the case if more than one has been encountered. If only one was encountered, the data element name could correspond to a list or a single value. This parser does not have access to a DTD or schema to check and so it is up to the caller to decide whether a list containing a single value represents a list of data elements or a single data element.

      Parameters:
        `elementName` - Data element name to check if more than one value with that element name has data available.
      Returns:
        Does the given data element name correspond to more than one deserialized value in this local handler?
      Throws:
        `NullPointerException` - The element name argument is `null`.

    - #### isSingleSubElement

          public final boolean isSingleSubElement(String elementName)
                                           throws NullPointerException

      Returns `true` if exactly one deserialized sub element value matching the given element name is available within this local handler. If the element name is not known, corresponds to an empty list or corresponds to a list of more than one value, `false` will be returned.

      Parameters:
        `elementName` - Sub element name to check if exactly one value with that element name has been deserialized.
      Returns:
        Does the given sub element name correspond to exactly one deserialized value in this local handler?
      Throws:
        `NullPointerException` - The element name argument is `null`.

    - #### isSingleDataElement

          public final boolean isSingleDataElement(String elementName)
                                            throws NullPointerException

      Returns `true` if exactly one value for a data element value matching the given element name is available within this local handler. If the element name is not known, corresponds to an empty list or corresponds to a list of more than one value, `false` will be returned.

      Parameters:
        `elementName` - Data element name to check if exactly one value with that element name has been deserialized.
      Returns:
        Does the given data element name correspond to exactly one data element value in this local handler?
      Throws:
        `NullPointerException` - The element name argument is `null`.

    - #### isDataElementPresent

          public final boolean isDataElementPresent(String elementName)
                                             throws NullPointerException

      Check if text content is available for a child data element of the given name.

      Parameters:
        `elementName` - Name of a child data element to use to check if text content is available.
      Returns:
        Is text content available for the given element name?
      Throws:
        `NullPointerException` - The element name argument is `null`.

    - #### isSubElementPresent

          public final boolean isSubElementPresent(String elementName)
                                            throws NullPointerException

      Check if a deserialized sub element value or values is/are available for the given sub element name.

      Parameters:
        `elementName` - Name of a child sub element to use to check if a sub element value or sub element values are available.
      Returns:
        Is/are sub element value/values available for the given element name?
      Throws:
        `NullPointerException` - The element name argument is `null`.

    - #### areAttributesPresent

          public final boolean areAttributesPresent(String elementName)
                                             throws NullPointerException

      Check if attributes are available for the given element name. If attributes are not available, this could be for two reasons:

      - An element of the given name was not encountered while parsing the children of the element associated with this local handler.
      - The element was encountered but defined no attributes.
      Parameters:
        `elementName` - Name of a data element of sub element to use to check for the presences of an attributes set.
      Returns:
        Are attributes available for the given element name?
      Throws:
        `NullPointerException` - The element name argument is `null`.

    - #### getInputStreamForName

          public InputStream getInputStreamForName(String streamName)

      Return the input stream with the given name from the collection of streams that has been attached to this content handler.

      Parameters:
        `streamName` - Name of the input stream to retrieve.
      Returns:
        Input stream associated with the given name, or `null` if not input streams are available or the given name does not map to an input stream.
      See Also:
        `MasterContentHandler.getInputStreamForName(java.lang.String)`

    - #### getBytesFromStream

          public byte[] getBytesFromStream(String streamName)
                                    throws IOException

      Find a named stream of data attached to the parent content handler, read it and return it as a byte array.

      Parameters:
        `streamName` - Name of the stream to read.
      Returns:
        Byte buffer containing the stream of the given name, or `null` if a stream of the given name could not be found.
      Throws:
        `IOException` - An error occurred when trying to read the given input stream.

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