Skip navigation links

Package uk.ac.starlink.hdx

Provides the structuring for the HDX system.

See: Description

Package uk.ac.starlink.hdx Description

Provides the structuring for the HDX system.

This is the package which defines the structure of the HDX system, registers new types, and is responsible for managing the implementations of the various factories required.

HDX is defined as a DOM. This does not mean that an HDX object necessarily is a DOM -- it could be represented as a Source, as a SAX stream, or ultimately not in an XML form at all -- however, it is defined using DOM terminology, and all operations on it are representable in those terms.

An HDX is a DOM Document node, which has a document element of type <hdx>, which in turn contains other elements of registered types. HDX does not define or constrain these other types (instead providing facilities for defining them), other than to require that they be defined in DOM terms.

The types are not generally processable using the DOM, however, and so they must be transformed into a Java object before work can be done on them. This transformation may involve significant (one-time) work, if the object has to be assembled from information in the DOM, or it may be trivial, if the DOM in fact mirrors some underlying object. During processing, the object will generally be manipulated using some interface defined as part of the resulting Java object's specification.

HDX types

All important elements in the HDX DOM correspond to types registered with the HDX system. Only those elements which correspond to registered types can be constructed as Java objects. However, not all elements must be registered -- elements which are embedded within important types, and which do not have to be children of the <hdx> element, do not have to be registered or have handlers.

Types are registered by creating an instance of class HdxResourceType, using the static method newHdxResourceType. See below for an example.

Important classes and interfaces

The two core classes in the Hdx package are:

HdxResourceType
Instances of this define the types known to Hdx. These instances encapsulate type information, including the methods which check type-validity of Hdx objects.
HdxFactory
This is the gateway to the Hdx system. This class marshalls the various factories responsible for creating objects and the DOM representations of them, and is responsible for normalising and validating files which purport to be Hdx instances.

The most important interfaces are:

HdxContainer
This is the type which represents an Hdx object as a whole. The first stage of processing a data object is to turn it from its original form -- a FITS or XML file, perhaps, or an object on the network -- into a HdxContainer. HdxFactory is what achieves this, possibly with the background help of an HdxDocumentFactory.
HdxFacade
This is how a Java class represents itself to the DOM world. See below.

The most important interfaces for implementors are:

HdxDocumentFactory
Implementations of HdxDocumentFactory are what constructs HdxContainers from URIs and URLs. A class which is able to construct a DOM from a particular class of URL -- such as a URL pointing to a FITS file, for example -- registers a HdxDocumentFactory instance with HdxFactory's registerHdxDocumentFactory: when HdxFactory is asked to construct a DOM by a call to its newHdxContainer methods, it works through the list of registered factories until one of them successfully constructs the DOM. The methods of this interface are not called directly by client code, but are implemented by those adding new file formats (such as FITS or HDS, say) to the Hdx system.
HdxResourceFactory
Implementations of the HdxResourceFactory type are responsible for exposing a DOM element as a Java object. The methods of this interface are not called directly by client code, but are implemented by those adding new types (such as Weather, say) to the Hdx system.
HdxFacade
This is the interface through which a Java object makes itself visible in DOM/Source terms. Interfaces such as Ndx or NDArray have a getHdxFacade method. This can be incorporated into a DOM based on HdxDocument by using that class's extension method HdxDocument.createElement(HdxFacade): the resulting element behaves exactly like a org.w3c.dom element, except that all its DOM-building (and optionally DOM-mutating) methods are handled by the HdxFacade, which knows exactly the state of the underlying object, and which can return the underlying object particularly easily.

The HdxContainerinterface is used by most code which wants to use Hdx objects. The two factory interfaces are not used by client code, but exist in order to be implemented by those extending the system.

Namespaces

Hdx objects may be synthesized from binary data files such as HDS or FITS files, or else they may be extracted from the DOMs constructed from XML files. If the thing (Element or URI) passed to method newHdxContainer corresponds to a registered Hdx type and it is in no namespace, then the input DOM is processed as you might expect.

The factory can also process elements in a more sophisticated way. If the element passed to newHdxContainer does not correspond to a registered type, or it is in the Hdx namespace, then the method will examine only those elements and attributes in the Hdx namespace (see W3C namespaces spec). This means that the Hdx information is able to be carried inside another unrelated XML file, invisible to a namespace-aware processor examinging only the `background' XML.

The Hdx namespace is defined to be http://www.starlink.ac.uk/HDX, which string is accessible as HdxResourceType.HDX_NAMESPACE. The Hdx DOM which is constructed from such an input element contains only the Hdx-registered elements, in no namespace, so that users of the DOM do not have to worry about the occasionally subtle details of namespace processing. Thus the XML file

    <rubbish xmlns:x="http://www.starlink.ac.uk/HDX">
      <x:hdx>
        <x:ndx>
          <x:data uri="file:/tmp/mydata.sdf"/>
        </x:ndx>
      </x:hdx>
    </rubbish>

is transformed into the simpler DOM

    <hdx>
      <ndx>
        <data uri="file:/tmp/mydata.sdf"/>
      </ndx>
    </hdx>

Changes made to the attributes in this transformed DOM are reflected in the original DOM.

Further transformations happen when a DOM is imported into Hdx. Firstly, the attribute `name' in the Hdx namespace is transformed into an element with that name. Secondly, if an Hdx type has a `hoist' attribute defined (see setHoistAttribute), then any text content of the element will be hoisted up to form the content of that hoist attribute. Finally, if the Hdx DOM which results from this does not have <hdx> as its top element, but instead an element which is a valid child of <hdx>, then it is inserted into a <hdx> element. Thus

    <mystructure>
      <mypointer x:name="ndx" xmlns:x="http://www.starlink.ac.uk/HDX">
        mydata.sdf
      </mypointer>
    </mystructure>

is transformed into

    <hdx>
      <ndx uri="mydata.sdf"/>
    </hdx>

and processed accordingly.

If you are particularly familiar with the W3C Namespaces spec, then you will have objected that the `uri' attribute in the first example was formally in no namespace, and should not therefore have been processed. This is true, but it is so unhelpfully counter-intuitive that as a special case, the normalisation process described here processes such no-namespace attributes in the Hdx namespace if the element is itself in the Hdx namespace, as is the case in the example above.

Usage: reading XML and other files

Use HdxFactory.getInstance().newHdxContainer(URI) to extract HDX objects from URIs, and method newHdxContainer(Element) to extract Hdx objects from DOMs, using the namespace mechanism described above.

Usage: defining new types

To define a new type, you must create a new HdxResourceType, using method HdxResourceType.newHdxResourceType(java.lang.String), and then act on the resulting object to register validators and constructors. For example, the (very simple) definition of the HdxResourceType.TITLE object consists of:

     TITLE = HdxResourceType.newHdxResourceType("title");
     TITLE.setHoistAttribute("value");
     TITLE.setElementValidator(new ElementValidator() {
         public boolean validateElement(Element el) {
             // A TITLE element is valid if it has an attribute "value"
             return HdxResourceType.match(el) == TITLE
                 && el.hasAttribute(TITLE.getHoistAttribute());
         }
     });

The hoist attribute means that, as described in the namespaces section above, the element <title>My title</title> is equivalent to the normalised form <title value="My title"/>.

The HdxResourceType.HDX type has a somewhat more complicated validator, plus the assertion

     HDX.setConstructedClass("uk.ac.starlink.hdx.HdxContainer");

that constructed (Java) objects must be instances of the HdxContainer interface.

This creation and registration code is located in the static initialiser of a suitable class. This registration is therefore performed whenever this class is loaded and initialised. That happens whenever an object of that class is created, or a static method invoked. The class may also be loaded explicitly by declaring some properties, as described in HdxResourceType.

New types may be declared in their own package, or in the package uk.ac.starlink.hdx.extension; non-Starlink types should not be declared in the uk.ac.starlink.hdx package, nor in any other package with prefix uk.ac.starlink.

For an example of a simple class, see the sample class SimpleWeather.java, included in the distribution.

Usage: adding new file formats

To add a new file format which can be given a DOM interface, you must create a class which implements HdxDocumentFactory, which turns a URL into a DOM Document.

Such extending classes are registered with the Hdx system using HdxFactory.registerHdxDocumentFactory(uk.ac.starlink.hdx.HdxDocumentFactory), by a mechanism which is described in the HdxFactory class documentation.

These factories can be arbitrarily clever. They can either create a simple DOM and wait for the work of reading the file to be done by the constructors registered with the type using HdxResourceType.registerHdxResourceFactory(uk.ac.starlink.hdx.HdxResourceFactory), or else the factory can construct the object, using a class which implements the HdxFacade interface, and then create an Element which uses that facade using HdxDocument.createElement(HdxFacade). For further details about this route, including an example, see the HdxDocumentFactory documentation.

That covers construction of a complete Hdx DOM from a URI. However, you should also handle, if appropriate, a reference to your new file format from within a DOM. In the case of the Ndx type, that can be done with a construction such as

     ndxType.registerHdxResourceFactory(new HdxResourceFactory() {
         public Object getObject(Element el)
                 throws HdxException {
             return new BridgeNdx(new DomNdxImpl(el));
         }
     });

where ndxType is the HdxResourceType object which this initialiser has obtained either from HdxResourceType.match("ndx") or, preferably, from its initialisation of the Ndx type using newHdxResourceType. The class DomNdxImpl is a class which is private to the Ndx package.

Related Documentation

See the Starlink web pages.

Skip navigation links

Copyright © 2023 Central Laboratory of the Research Councils. All Rights Reserved.