In principle, there is no limit on the amount of data that can be stored within a Metadata object. In fact, data files containing FITS or HDF formatted data often contain quite a bit of metadata. It may be expensive to load all the data into the Metadata object, especially if the data must be obtained from the network. If the user ends up requesting only a few of the metadata elements, loading all of the data would be quite a waste. However, one may not know ahead of time which data will be requested. To help with this dilemma is a special metadatum class called Metarunner.
An implementation of the Runnable interface, the Metarunner class has the job of obtaining a metadatum value on demand. If one has a piece of metadata that is expensive to load, instead of loading the actual value, one loads instead a Metarunner object for that metadatum. When a client object requests the metadatum, the Metadata object first looks for a static value in the usual way; if none exists, it will call on the Metarunner to fetch and return the value. The Metadata object will remember the value for the next time it is requested.
To clients of Metadata objects, use of Metarunners is completely transparent; users may not realize that this dynamic loading is taking place. Metarunner's are usually only dealt with when loading Metadata lists. A Metarunner is usually designed for a specific metadatum or set of metadata that are all fetched in the same way. To do so, one must sub-class the Metarunner class and override the getDatum() method. This method returns a ValueAndStatus object, containing an Object to hold the value and an int to hold the status. The possible status values should include the values defined by the Metarunner class which are listed in Table 2.5. The sub-class may support additional error codes; however, all error codes greater than or equal to 2 should indicate that the value returned is invalid.
Table 1: Metarunner Status Values
To have a Metadata use the Metarunner, one should save the Metarunner in the list using the name of metadatum it fetches appended by the value of string Metadata.METARUNNER_TAG (``:Metarunner''). When the a client requests the metadata for the first time, the primary list will not contain a value. At this point, the Metadata object will look for the existance of an associated Metarunner. If it finds a Metarunner, it runs it and saves the result into the primary list. The Metarunner will only get rerun if the first attempt failed to produce a good value (i.e. error status equal to Metarunner.OK).
In general, the Metarunner class offers the user several ways to fetch and return a value:
One example of a Metarunner class used by the Horizon package is the ObjectCloner. This class is used to protect updatable classes being stored in Metadata list, such as ``defaultSlice'' (of the horizon schema, see App. A.2). The getDatum() method simply returns a clone of another object the ObjectCloner has stored internally as a protected field and which was set at construction. This object is stored as a Metarunner object in place of the metadatum itself. Furthermore, the ObjectCloner's getDatum() method always returns a status of RUN_PROBLEM upon successful completion; this prevents the Metadata list from saving the updatable object by itself afterward and ensures that the ObjectCloner will always get called the next time the client requests the metadatum value.