    All Packages  Class Hierarchy  This Package  Previous  Next  Index

# Class ncsa.horizon.util.Metadata

    java.lang.Object
       |
       +----java.util.Dictionary
               |
               +----java.util.Hashtable
                       |
                       +----ncsa.horizon.util.Metadata

public class Metadata
extends Hashtable

a hashtable where keys are String objects and values are Object objects. Like java.util.Properties, it contains an internal default value list. Data contained within Metadata within Metadata are directly accessible. Also supported is the transparent loading of data into the hashtable only at the point when the user first requests them.

Within the Horizon package, Metadata objects hold data that describe other data. For example, image data sets can have metadata associated with them that can describe things like the number of dimensions it has, the origin of the data, etc; this can information can usually be accessed through Viewable method, getMetadata(). CoordinateSystem objects also have metadata associated with them that provide the parameters that describe the system.

Users of this class should remember that metadata have an assumed type that is implicitly agreed upon by all classes that access it. For example, classes in ncsa.horizon.coordinates package assume that the metadatum named "naxes" to be of type Integer. If a class finds that a metadatum has an unexpected type, the class may throw a MetadataTypeException. (See CoordMetadata for more details about coordinate-related metadata.)

The only pre-defined metadata names are "schema" and "schemaVersion". The "schema" metadatum is a String that identifies the set of metadata names in use by this Metadata object, along with the types and logical meaning of those names. The "schemaVersion" is also a String to identify the version of the schema.

Accessing Hierarchical Metadata

Each piece of Metadata can be accessed through its name (often referred to as its keyword), represented as a String, using the getMetadatum(String) method. A metadatum value is set using the put method (from the super-class, Hashtable).

Special support is provided for hierarchical metadata. For example, a Metadata object can contain another Metadata object. It can also contain one or more Metavector objects, each one containing an array of metadata of the same type. The Metadata class supports this notion by allowing one to request "sub-metadata" directly with the getMetadatum(String key) method. If the key string contains a period ("."), the substring to the left of the period is taken to be the name of a metadatum of type Metadata; the substring to the left of the period is taken to be the name of a metadatum contained within that metadata object. For example, the following code,

        Metadata md;
        ...
        Metadata cmd = (Metadata) md.getMetadatum("coordinates");
        String name = (String) cmd.getMetadatum("name");

is equivalent to:

        String name = (String) md.getMetadatum("coordinates.name")

In fact, the latter is actually safer and more efficient. Similarly, if a Metadata object contains a Metavector object as one of its items, one can access an element of the Metavector by appending "`[n]`" to the name of the Metavector, where n is an integer specifying the desired array index. For example,

        Object element = md.getMetadatum("Axes[1]");

returns the object at index 1 (the second element) of the Metavector called "Axes".

Use the "sub-metadata" syntax, one can directly access hierarhical metadata of arbitrary depth. For example, the following is the most efficient way (in terms of memory and time) of access the specified sub-metadatum:

        String name = (String) md.getMetadatum("coordinates.Axes[1].name");

Note that one cannot use the "sub-metadata" syntax to update hierarchical metadata.

Default Metadata

Metadata objects can store two sets of data within themselves: primary data and default data. Calls to getMetadatum(String) will return requested data from the primary set; if it does not exist there, the value in the default searched for a value. (To prevent search of the default set, one should call getMetadatum(String, null).) The default data can only be set during construction. Primary data may be updated via the put and copyMetadata(Metadata) methods. The internally stored default metadata provides a way for managers of metadata to protect their data from updates by other objects. If a metadata manager has a Metadata it wants other objects to read from but not write into, it can create a new Metadata object that has the original as the default. The other users of the new Metadata can then read the elements and even override them without affecting the original Metadata object.

One other feature of the support for default values is that it allows the originator of Metadata (the object that has a reference to the default Metadata) to update the defaults after the Metadata has been created and passed on. Such changes would be seen by those objects that have not overriden the defaults. Client objects that prefer that their copy of the Metadata not be connected the originator in this way can "detach" it via the detach() method. Other methods are provided for obtaining "detached" copies of the data, detachedClone(), and cloneDefaults(). (Note that the standard clone() produces a Metavector whose defaults are "attached" to the same object as the original.)

One should note that the defaults protection only applies to the internal default Metadata container itself, not its elements. That is, the value returned by getMetadatum(String) is the original version of the datum and not a copy. Thus, there may be any number of references to the datum held by other objects. (The datum is protected only if it is of a type that is not internally editable. For example, the value of an Integer or String object cannot be updated; however, if the datum is of type Stack, the data internal to that Stack is not protected from updates.) An exception to this is when the value is obtained from the default list and is of type Metavector or Metadata; in this case, the meta-container is placed as the default list in a new meta-container before being passed on.

Dynamic Metadata Loading

Some metadata may be costly to load into memory, for example, if it needs to be downloaded from the network or it requires an expensive computation. The effort to load the data into a Metadata object may be wasted if the user never requests the data. The Metadata class provides a mechanism for one to store procedures, in the form of Metarunner objects, for obtaining metadata. When a user requests a metadatum object for which there exists a Metarunner object, the Metarunner is executed and the resulting value is returned to the user as well as loaded into the hashtable for future requests.

To make use of this capability, programmers should sub-class the Metarunner class, overridding the getDatum() method. The Metarunner object is then stored in the Metadata object using the name of metadatum appended with the String Metadata.METARUNNER_TAG. When the user later requests a named metadatum, the Metadata object first looks for a static value in its hashtable. If it does not exist, then the Metadata object looks for a Metarunner object that can obtain the value. Failing that, the default list is consulted (which might also engage a Metarunner object). If the Metarunner does exist and successfully returns a value, the value is stored in the primary hastable as a static value.

Support for Metarunner objects is meant by default to be transparent; the user is given some explicit control and access to the objects. To prevent the execution, one can set the public boolean field, executeRunners to false. The getRunnerNames() method returns the names of metadata (without the METARUNNER_TAG appended) that have Metarunners associated with them. In contrast, the MetadatumNames() returns the only the names for which there currently exists static values (including the modified names pointing to Metarunner objects). Since the latter method is expected to be used to step through each metadata value (say to copy it to another container), this behavior prevents the unintended execution of costly Metarunners.

##

defaults
  the default Metadata values
executeRunners
  true if Runnable objects should be executed to obtain values for requested metadata when available.
METARUNNER_TAG
  the suffix to be appended to a metadatum name to refer to a Metarunnable object that can fetch the value of that metadatum.
schema
schemaVersion

##

Metadata()
  Creates an empty metadatum list.
Metadata(int)
  Creates an empty metadatum list with an initial capacity
Metadata(int, Metadata)
  Creates an empty metadatum list with an initial capacity and specified defaults.
Metadata(Metadata)
  Creates an empty metadatum list with specified defaults.

##

clone()
  Clones this metadata object.
cloneDefaults()
  clone the defaults metadata.
copyMetadata(Hashtable)
  Copy all the data from a Hashtable whose keys are of type String into the primary data list.
copyMetadata(Metadata)
  Copy all the data from another Metadata object into the primary data list.
deepClone()
  create a semi-deep clone.
detach()
  replace the internal default Metadata with a copy (via deepClone()), detaching control of the defaults from the originator of this Metadata.
detachedClone()
  Like clone(), except that a copy of the defaults metadata is also made.
fetchDatum(String, Metarunner)
  Execute a Metarunner that fetches the value of a specifed key and stores the result into this Metadata list
fetchMetadatum(String)
  execute the runner (if it exists and is accessible) for the specified key, and return its value.
getDefaults()
  return a new Metadata object with the same default data but with no primary data
getMetadatum(String)
  Gets a metadatum with the specified key.
getMetadatum(String, boolean)
  Gets a metadatum with the specified key.
getMetadatum(String, Object)
  Gets a metadatum with the specified key and default.
getMetadatum(String, Object, boolean)
  Gets a metadatum with the specified key and default.
getRunnerNames()
  Enumerate the keys having Metarunner objects associated with them
giveDefaults(Metadata)
  Copy the default metadata of this Metadata object to the defaults of another Metadata object.
metadatumNames()
  Enumerates all the keys.
removeAllMetadata()
  remove the primary key/value pairs from this Metadata object, leaving the defaults.
setDefaults(Metadata)
  Set the default Metadata of this Metadata object.
setSchema(String)
  set the name of the schema used by this Metadata object
setSchemaVersion(String)
  set the version of the schema used by this Metadata object
toString()
  attempt to convert contents to a multi-line String (useful for debugging

##

schema

      public final static String schema

schemaVersion

      public final static String schemaVersion

METARUNNER_TAG

      public final static String METARUNNER_TAG

  the suffix to be appended to a metadatum name to refer to a Metarunnable object that can fetch the value of that metadatum.

defaults

      protected Metadata defaults

  the default Metadata values

executeRunners

      public boolean executeRunners

  true if Runnable objects should be executed to obtain values for requested metadata when available.

##

Metadata

      public Metadata()

  Creates an empty metadatum list.

Metadata

      public Metadata(Metadata defaults)

  Creates an empty metadatum list with specified defaults.
  Parameters:
    defaults - the defaults

Metadata

      public Metadata(int initialCapacity)

  Creates an empty metadatum list with an initial capacity

Metadata

      public Metadata(int initialCapacity,
                      Metadata defaults)

  Creates an empty metadatum list with an initial capacity and specified defaults.

##

setSchema

      public void setSchema(String in)

  set the name of the schema used by this Metadata object

setSchemaVersion

      public void setSchemaVersion(String in)

  set the version of the schema used by this Metadata object

getMetadatum

      public Object getMetadatum(String key)

  Gets a metadatum with the specified key. If the key is not found in this metadatum list, it tries the defaults. This method returns null if the metadatum is not found.
  Parameters:
    key - the metadatum name

getMetadatum

      public Object getMetadatum(String key,
                                 boolean doRun)

  Gets a metadatum with the specified key. If the key is not found in this metadatum list, it tries the defaults. This method returns null if the metadatum is not found.
  Parameters:
    key - the metadatum name
    doRun - if true, a Runnable object should be executed to obtain the requested value when available; overrides the value of executeRunners

getMetadatum

      public Object getMetadatum(String key,
                                 Object defaultValue)

  Gets a metadatum with the specified key and default. This method returns defaultValue if the metadatum is not found.

getMetadatum

      public Object getMetadatum(String key,
                                 Object defaultValue,
                                 boolean doRun)

  Gets a metadatum with the specified key and default. This method returns defaultValue if the metadatum is not found.

fetchDatum

      protected Object fetchDatum(String key,
                                  Metarunner fetcher)

  Execute a Metarunner that fetches the value of a specifed key and stores the result into this Metadata list
  Parameters:
    key - name of metadatum that the Metarunner will fetch.
    fetcher - the Metarunner object to execute

getRunnerNames

      public synchronized Enumeration getRunnerNames()

  Enumerate the keys having Metarunner objects associated with them

fetchMetadatum

      public Object fetchMetadatum(String key)

  execute the runner (if it exists and is accessible) for the specified key, and return its value. The static value will be updated only if it does not exist or is equal to null. Runners from the default list are inaccessible if a static value or a runner exists in the primary array. If a runner does not exist or is inaccessible, the result is equivalent to getMetadatum();

copyMetadata

      public void copyMetadata(Hashtable from)

  Copy all the data from a Hashtable whose keys are of type String into the primary data list. Data with non-String keys are ignored.

copyMetadata

      public void copyMetadata(Metadata from)

  Copy all the data from another Metadata object into the primary data list. (Data with non-String keys are ignored.) Metarunner objects are copied without being executed.

setDefaults

      public synchronized void setDefaults(Metadata to)

  Set the default Metadata of this Metadata object. The specified defaults replace the one previously in use. This effectively "detaches" this Metadata from its originator and "attaches" it to the caller of this method. If no other object holds a reference to the old defaults, it will get garbage-collected.

getDefaults

      public Metadata getDefaults()

  return a new Metadata object with the same default data but with no primary data

detach

      public final synchronized void detach()

  replace the internal default Metadata with a copy (via deepClone()), detaching control of the defaults from the originator of this Metadata. Users should call this method to prevent the originator from updating the defaults later.

giveDefaults

      public void giveDefaults(Metadata to)

  Copy the default metadata of this Metadata object to the defaults of another Metadata object. Most applications should not need to call this method; in fact, they should avoid it. Because the copy is shallow, it opens the possibility for the data internal to the items held within the default list to become corrupted
  Parameters:
    to - the other Metadata object to copy defaults to

removeAllMetadata

      public void removeAllMetadata()

  remove the primary key/value pairs from this Metadata object, leaving the defaults.

metadatumNames

      public Enumeration metadatumNames()

  Enumerates all the keys.

toString

      public String toString()

  attempt to convert contents to a multi-line String (useful for debugging
  Overrides:
    toString in class Hashtable

clone

      public Object clone()

  Clones this metadata object. The data themselves are not cloned, and the defaults are still in control of this metadata's originator.
  Overrides:
    clone in class Hashtable

detachedClone

      public Metadata detachedClone()

  Like clone(), except that a copy of the defaults metadata is also made. This provides a fully metavector object that is fully detached from the originator of this metadata object; that is, the originator can not change the defaults of the new metadata. The elements within both the primary and default arrays are not cloned.

cloneDefaults

      public Metadata cloneDefaults()

  clone the defaults metadata. The resulting metadata object will not have a defaults list of its own and, therefore, will be detached from the control of other objects. The data held within both the primary and default hashtables are not cloned.

deepClone

      public synchronized Metadata deepClone()

  create a semi-deep clone. This method is like clone(), except that the Metadata and Metavector objects contained within are replaced with their own clones (using their respecitive deepClone() methods).

    All Packages  Class Hierarchy  This Package  Previous  Next  Index