All Packages Class Hierarchy This Package Previous Next Index
java.lang.Object
|
+----java.util.Dictionary
|
+----java.util.Hashtable
|
+----ncsa.horizon.util.Metadata
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.
public final static String schema
public final static String schemaVersion
public final static String METARUNNER_TAG
protected Metadata defaults
public boolean executeRunners
public Metadata()
public Metadata(Metadata defaults)
public Metadata(int initialCapacity)
public Metadata(int initialCapacity,
Metadata defaults)
public void setSchema(String in)
public void setSchemaVersion(String in)
public Object getMetadatum(String key)
public Object getMetadatum(String key,
boolean doRun)
public Object getMetadatum(String key,
Object defaultValue)
public Object getMetadatum(String key,
Object defaultValue,
boolean doRun)
protected Object fetchDatum(String key,
Metarunner fetcher)
public synchronized Enumeration getRunnerNames()
public Object fetchMetadatum(String key)
public void copyMetadata(Hashtable from)
public void copyMetadata(Metadata from)
public synchronized void setDefaults(Metadata to)
public Metadata getDefaults()
public final synchronized void detach()
public void giveDefaults(Metadata to)
public void removeAllMetadata()
public Enumeration metadatumNames()
public String toString()
public Object clone()
public Metadata detachedClone()
public Metadata cloneDefaults()
public synchronized Metadata deepClone()
All Packages Class Hierarchy This Package Previous Next Index