Next: The World Coordinate System Up: The Horizon Metadata Model Previous: Handling Arrays: The Horizon

## On-Demand Data Loading: The Horizon `Metarunner` Class

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 `Metarunner`s 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:

- call the `getDatum` method directly.
- call the `run` method, then call `getLastValue`.
- call the static `fetchDatum` method (equivalent to the previous 2-step procedure).
- pass this object as a Runnable to a Thread, execute the Thread, wait for it to finish, and then call `getLastValue`.

If `run` completes without interruption, then an internally stored run counter (accessible via `getRunCount()`) is incremented and the error state is updated. If `getDatum()` returns with a state of `OK` or `RUN_PROBLEM`, the value is stored internally for access via getLastValue(). The `Metadata` class calls the `fetchDatum` method when it needs to turn to a `Metarunner` to obtain a value; it remembers the result only if the error status is equal to OK.

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.

Next: The World Coordinate System Up: The Horizon Metadata Model Previous: Handling Arrays: The Horizon