uk.ac.starlink.hdx
Interface HdxFacade

All Superinterfaces:
Cloneable
All Known Implementing Classes:
AbstractHdxFacade, BridgeNDArray.BridgeNDArrayHdxFacade, BridgeNdx.BridgeNdxHdxFacade

public interface HdxFacade
extends Cloneable

An HdxFacade maintains an object's representation as a DOM. As well as generating the DOM representation, this type provides optional support for altering the underlying object through a DOM interface. Although it is implementations of this interface which are ultimately responsible for generating XML in the HDX system, the methods here are not intended to be invoked directly by application code: instead, use the method HdxFactory.newHdxContainer(HdxFacade), and use the DOM and Source methods on the resulting HdxContainer. Though this may seem roundabout, it means that the resulting XML has been through whatever normalization or relativization steps are required.

XXX getDOM method is almost certainly disappearing! Thus these class comments need a rewrite.

Only the synchronizeElement, getObject and getHdxResourceType methods need have non-trivial implementations. This interface can most efficiently be implemented by extending AbstractHdxFacade.

The getDOM and getSource methods, can be straightforwardly implemented in terms of synchronizeElement, and this is what is done in AbstractHdxFacade. These two methods, getDOM and getSource, are complementary: one is a convenience interface for the other. Which is which, however, will vary between implementations, and client code should call whichever one of the two is actually required.

The remaining methods, addChildBefore, replaceChild and setAttribute, which mutate the DOM, may have trivial implementations which always return null, indicating that the DOM is effectively read-only. If it is appropriate for the facade to support modification, then these three DOM-mutation methods are sufficient to support all the relevant methods of the Element interface.

Version:
$Id$
Author:
Norman Gray

Method Summary
 boolean addChildBefore(Element parent, Element newChild, Element refChild)
          Adds a new child to an element.
 Object clone()
          Creates and returns a copy of this object.
 HdxResourceType getHdxResourceType()
          Obtains the HdxResourceType which this is a facade for.
 Object getObject(Element el)
          Obtains the object which the given Element is a facade for.
 Source getSource(URI base)
          Produces a Source representing the object.
 boolean replaceChild(Element parent, Element newChild, Element oldChild)
          Replaces or removes a child.
 boolean setAttribute(Element el, String name, String value)
          Sets an attribute on an element.
 Object synchronizeElement(Element el, Object memento)
          Adds attributes and children to the given element, to represent the current state of the object as a DOM.
 

Method Detail

synchronizeElement

Object synchronizeElement(Element el,
                          Object memento)
                          throws HdxException
Adds attributes and children to the given element, to represent the current state of the object as a DOM. The implementing object should add or update elements and attributes on the given element using the Document obtained by invoking Node.getOwnerDocument() on the element. This Document will in fact be an instance of HdxDocument, which implements the standard Document interface with the addition of HdxDocument.createElement(HdxFacade), which the implementing code is therefore free to use (this is an understatement -- the entire point of this interface is to give an implementing class the opportunity of using this method).

The element will have the type this.getHdxResourceType().xmlname().

This method is called frequently, and the implementing object should therefore take care to do no more work than is necessary. To assist in this, the caller will preserve a memento on behalf of the implementor. This memento is the object returned by this method, which is re-presented when the synchronizeElement method is next called (this is an example of `memento' pattern, although that is more commonly associated with undo actions than the cache-like operation described here). If the implementing object needs to preserve some state, to remind it of its own state when it last synchronised the element, then it should wrap that state in some object or other and return it from this method. This might be as simple as a hash-code.

The first time this method is called, the memento will be null.

The returned memento may be null if, for example, the implementor can extract all its relevant state information from the DOM it receives in the Element; or if the object is immutable, so that the Element attributes and children are correct if they are there at all. This null memento will be duly returned to the implementor on any future invocation. In such a case, the implementor might need to be careful to distinguish this returned null memento from the null memento provided when the method is called the first time.

It is perfectly feasible for the implementor to return itself as the memento.

Parameters:
el - an element which is to be made consistent with the current state of the object
memento - either null, if this is the first time this method has been called, or the object which was returned by this method last time it was called (which may be null if that is what the method chose to return)
Returns:
an object or null, which is to be returned to the method next time it is called
Throws:
HdxException - if it is for some reason impossible to update the DOM. The method should regard this as something akin to a `can't happen' error: this thrown exception will be converted to a DOMException if that is reasonable for the caller, but if not, may be converted to a PluginException.

getSource

Source getSource(URI base)
                 throws HdxException
Produces a Source representing the object.

This method, and #getDOM are partners, in the sense that one is a convenience interface for the other, but which one is which depends on the implementation. Since the conversion between a DOM and a Source might possibly require some processing, client code should use the method which returns the type of object it actually wants.

The XML in general may contain URLs, for instance referencing the array components of the NDX. How these are written is determined by the base parameter; URLs will be written as relative URLs relative to base if this is possible (e.g. if they share a part of their path). If there is no common part of the path, including the case in which base is null, then an absolute reference will be written.

Parameters:
base - the base URI against which URIs written within the XML are considered relative. If null, all are written absolute.
Returns:
a Source representing the object
Throws:
HdxException - if the Source cannot be generated fo some reason
See Also:
SourceReader

setAttribute

boolean setAttribute(Element el,
                     String name,
                     String value)
Sets an attribute on an element. If an attribute is `set' to a null value, it is removed.

This is an optional operation. An implementation may simply return null to indicate that this operation is not supported.

Parameters:
el - the element which is to have the attribute set
name - the attribute which is to be set
value - the new value of the attribute. If the value is null, the attribute is removed. Setting the value to the empty string is allowed, and is not the same as setting it to null.
Returns:
true if the operation is supported and succeeded, or false if the operation is not supported in general, or failed in this case

addChildBefore

boolean addChildBefore(Element parent,
                       Element newChild,
                       Element refChild)
Adds a new child to an element.

This is an optional operation. An implementation may simply return null to indicate that this operation is not supported.

Parameters:
parent - the element which is to receive the new child
newChild - The child to be added
refChild - if non-null, the new child is to be inserted before refChild. If refChild is null, the new child is to be appended to the end of the list of children.
Returns:
true if the operation is supported and succeeded, or false if the operation is not supported in general, or failed in this case

replaceChild

boolean replaceChild(Element parent,
                     Element newChild,
                     Element oldChild)
Replaces or removes a child.

This is an optional operation. An implementation may simply return null to indicate that this operation is not supported.

Parameters:
parent - the element which is to have its children changed
newChild - the replacement element. If this is null, then oldChild is deleted.
oldChild - the element which is to be replaced.
Returns:
true if the operation is supported and succeeded, or false if the operation is not supported in general, or failed in this case

getObject

Object getObject(Element el)
                 throws HdxException
Obtains the object which the given Element is a facade for. The caller should know what (Java) type of object this will be (that is, Ndx, HdxContainer, or the like), and will therefore be able to cast the result appropriately.

The returned element must match the class appropriate for the Hdx type this element corresponds to. That is the return value obj must be such that the following are true

for any instance facade of this interface, and if el is the Element which this facade is linked to.

Parameters:
el - an Element which is to be transformed into an object
Returns:
the Java object which this element is a facade for. The object must not be null.
Throws:
HdxException - if the facade does not know how to recover the object type it has been asked for. This will also happen if the element el does not correspond to a known HdxResourceType.

getHdxResourceType

HdxResourceType getHdxResourceType()
Obtains the HdxResourceType which this is a facade for.

This is not (just) a convenience method. Although the same information is retrievable by calling getSource(java.net.URI), and calling HdxResourceType.match(Element) on the top element obtained from it,

  1. calling getSource may involve significant processing, and
  2. it is not trivial to retrieve the top element from a Source, since the root of the resulting document (matched by the XPath /) is not guaranteed to be the `top' node of the DOM (see DOMSource.DOMSource(Node))

Returns:
the HdxResourceType this facade represents

clone

Object clone()
Creates and returns a copy of this object.

The AbstractHdxFacade skeleton implementation implements this as simply

 public Object clone() { return super.clone(); }
 
which is generally suitable. If, however, the underlying object, or its DOM, is mutable, and particularly if the addChildBefore(), replaceChild() and setAttribute() methods are implemented, the implementation should very probably add a cleverer clone() method. Recall that if clone() is overridden, equals() and hashCode() should be overridden also.



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