VisAD / Java Design Bill Hibbard 17 July 97 The primary issue for exploiting JDK 1.1 is adapting the VisAD class hierarchy to RMI. In order to do this, the basic Data class hierarchy is replicated four times: as interfaces (which extend Remote but have both local and remote implementations), as remote interfaces (only have remote implementations), as local implementations, and as remote implementations (which are adapters for local implementations). For convenience, the interface, remote interface and local implementation hierarchies are collapsed together for Tuple, Set and Scalar. Furthermore, the remote hierarchy is limited to RemoteDataImpl (abstract), RemoteFunctionImpl (abstract) and RemoteFieldImpl, a remote adapter for local Field-s and FlatField-s. Other Data classes cannot be remote (but DataReference-s bound to them can be - see below). If we decide that other Data classes need to be remote, the basic design pattern of four parallel hierarchies can be elaborated to other Data classes. The interface hierarchy includes both Field (which is implemented by the local FieldImpl) and RemoteField (which extends Remote and is implemented by the remote RemoteFieldImpl). The rationale is to allow any Field reference to be either local or remote, but not to force access to local objects to go through the Remote interface. This pattern is also used for DataReference and Display. Note, special thought must be given to calls to hashCode, equals, toString and clone for remote implementations - these methods apply to the local stubs rather than the remote objects. In particular, the remote implementation hierarchy should not adapt these methods from the local implementation hierarchy. Here is how the Data class hierarchy is adapted to RMI: // interface hierarchy public interface Data extends Remote; public interface Function extends Data; public interface Field extends Function; // interfaces for Remote Data classes public interface RemoteData extends Data; public interface RemoteFunction extends Function; public interface RemoteField extends Field; // local implementation hierarchy // (collapsed with interface hierarchy for Tuple, Set and Scalar) public abstract class DataImpl implements Data, Cloneable, Serializable; public abstract class FunctionImpl extends DataImpl implements Function; public class FieldImpl extends FunctionImpl implements Field; public class FlatField extends FieldImpl; public class Tuple extends DataImpl; etc public class Set extends DataImpl; etc public class Scalar extends DataImpl; etc // remote implementation hierarchy // (adapter for local implementation hierarchy) public abstract class RemoteDataImpl extends UnicastRemoteObject implements RemoteData; // adapter for DataImpl public abstract class RemoteFunctionImpl extends RemoteDataImpl implements RemoteFunction; // adapter for FunctionImpl public class RemoteFieldImpl extends RemoteFunctionImpl implements RemoteField; // adapter for FieldImpl and FlatField VisAD also supports remote DataReference objects and remote Action and Display objects. Here is how the DataReference class is adapted to RMI: // interface hierarchy public interface DataReference extends Remote; public interface RemoteDataReference extends DataReference; // local implementation hierarchy public class DataReferenceImpl implements DataReference; // remote implementation hierarchy // (adapter for local implementation hierarchy) public class RemoteDataReferenceImpl extends UnicastRemoteObject implements RemoteDataReference; // adapter for DataReferenceImpl Here is how the Action and Display classes are adapted to RMI: // interface hierarchy public interface Action extends Remote; public interface Display extends Action; // interfaces for Remote Data classes public interface RemoteAction extends Action; public interface RemoteDisplay extends Display; // local implementation hierarchy public class ActionImpl implements Action, Runnable; public class DisplayImpl extends ActionImpl implements Display; // remote implementation hierarchy // (adapters for local implementation hierarchy) class RemoteActionImpl extends UnicastRemoteObject implements RemoteAction; // adapter for ActionImpl class RemoteDisplayImpl extends RemoteActionImpl implements RemoteDisplay; // adapter for DisplayImpl Data, DataReference and Action objects link like this: one-to-many many-to-many remote: RemoteData <--> RemoteDataReference <--> RemoteAction | | | adapts adapts adapts | | | local: DataImpl <--> DataReferenceImpl <--> ActionImpl DataReference.incTick() is invoked every time: 1. DataReference is linked to a new Data object (given the immutability of most Data classes, this is the most common form of data change). 2. The local and mutable Data object referenced by DataReference changes value (remote and mutable Data objects just do an IncTick that must be polled by DataReference). This causes a DataChangedOccurrence (note Java Events don't work remotely) to be sent to every Action linked to DataReference. In order for VisAD to be scalable, a set of policies are defined for pacing the delivery of DataChangedOccurrence-s. Each DataReference and Action defines the following set of policy preferences: 1. For local links, choice of: a. Throttle DataChangedOccurrence-s by waiting for acknowledgement of previous DataChangedOccurrence before sending next. b. DataReference delivers DataChangedOccurrence-s at most once per specified time interval (this requires a thread in DataReference). c. Action polls DataReference for DataChangedOccurrence at most once per specified time interval (Action already has a thread). d. DataChangedOccurrence-s delivered to Action immediately. 2. Time interval for choices 1.b. or 1.c. 3. Same choices a, b, c, d for remote links. 4. Time interval for choices 3.b. or 3.c. When a DataReference and an Action are linked, they negotiate these policies. Where they disagree, the order of precedence is a, b, c, d, and the longer time interval takes precedence. The RemoteDataReferenceImpl adapter for getData() decides whether to return Field-s by copy (FieldImpl, FlatField) or remote reference (RemoteFieldImpl). All other Data classes are returned by copy. The Field interface defines a method local(): local Field-s return 'this' and remote Field-s return their AdaptedField (i.e., a local copy is returned). Thus the decision to replace remote access to a Field or FlatField object with local access (by sending a copy to the client) can be made by either the client or the server. Summary of methods of Action / Display, DataReference, and Data: Action /** invokes ref.addDataChangedListener; RemoteActionImpl.addReference invokes ActionImpl.adaptedAddReference */ public abstract void addReference(DataReference ref) throws VisADException, RemoteException; /** RemoteActionImpl.removeReference invokes ActionImpl.adaptedRemoveReference */ public abstract void removeReference(DataReference ref) throws VisADException, RemoteException; /** 'Action' is the 'DataChangedListener' interface; cannot do it properly since Action cannot extend both Remote and EventListener (via DataChangedListener), and since EventObjects cannot be remote (EventObject.Source is transient) */ public abstract void dataChanged(DataChangedOccurrence e) throws VisADException, RemoteException; Display /** RemoteDisplayImpl.addReference invokes DisplayImpl.adaptedAddReference */ public abstract void addReference(DataReference ref, ConstantMap[] constant_maps) throws VisADException, RemoteException; public abstract void addMap(ScalarMap map) throws VisADException, RemoteException; public abstract void clearMaps() throws VisADException, RemoteException; public abstract void addRenderer(Renderer renderer) throws VisADException, RemoteException; public abstract void clearRenderers() throws VisADException, RemoteException; DataReference /** invokes d.addReference; RemoteDataReferenceImpl.setData invokes DataReferenceImpl.adaptedSetData */ public abstract void setData(Data d) throws VisADException, RemoteException; public abstract Data getData() throws VisADException, RemoteException; public abstract long getTick() throws VisADException, RemoteException; public abstract long incTick() throws VisADException, RemoteException; /** RemoteDataReferenceImpl.addDataChangedListener invokes DataReferenceImpl.adaptedAddDataChangedListener */ public abstract void addDataChangedListener(Action a) throws VisADException, RemoteException; /** RemoteDataReferenceImpl.removeDataChangedListener invokes DataReferenceImpl.adaptedRemoveDataChangedListener */ public abstract void removeDataChangedListener(Action a) throws VisADException, RemoteException; Data /** DataImpl.local() returns 'this' RemoteDataImpl.local() returns 'AdaptedData' */ public abstract DataImpl local() throws VisADException, RemoteException; /** RemoteDataImpl.addReference invokes DataImpl.adaptedAddReference */ public void addReference(DataReference r) throws VisADException, RemoteException; /** RemoteDataImpl.removeReference invokes DataImpl.adaptedRemoveReference */ public void removeReference(DataReference r) throws VisADException, RemoteException; public abstract boolean isMissing() throws VisADException, RemoteException; public abstract Data binary(Data data, int op, int sampling_mode, int error_mode) throws VisADException, RemoteException; public abstract Data add(Data data, int sampling_mode, int error_mode) throws VisADException, RemoteException; public abstract Data unary(int op, int sampling_mode, int error_mode) throws VisADException, RemoteException; public abstract MathType getType() throws VisADException, RemoteException; DISPLAY ARCHITECTURE 1. Display class Runnable list of (Renderer, list of (DataReference, list of ConstantMap)) each Renderer renders list of DataReference for special color compositing, mapping one data object onto a surface defined by another, etc each DataReference has a list of ConstantMap objects for spatial Offset, default Color, etc list of ScalarMap objects including ConstantMap objects Renderer checks metadata and MathType of Data for feasibility also looks at samplings to determine feasibility may do adaptable level-of-detail DisplayRenderer metadata visualization (spatial axes, skewt background, etc) merge scene graphs, mark as retained or compiled-retained DisplayRealType values determined by (in priority order): a. Data object RealType values mapped via ScalarMap-s b. ConstantMap-s in DataDisplayLink c. ConstantMap-s in Display d. DisplayRealType.DefaultValue 2. No direct manipulation Special Renderers for 3-D UI components embedded in 3-D display checks metadata and MathType of Data for feasibility updates attached DataReference-s and uses them for default values MathType-s may be complex (e.g., FlatField-s) 3. Display events changes to Control-s may trigger re-transform or re-render delegation event model (JDK 1.1) cannot be used remotely 4. Metadata visualization 5. User extensibility Renderer DisplayRenderer DisplayRealType-s DisplayTupleType-s 6. Clipping 7. Spatial cells Set Cell type Dimension point 0 line 1 triangle 2 rectangle 2 tetrahedron 3 rectangular solid 3 a. If Field Domain is mapped to Spatial then may use Field sampling Cells for Spatial Field b. Contour, Flow and Shape create derived cells c. Otherwise, use points (i.e., 0-D Cells) Need Set method(s) to enumerate Cells, but not one-at-a-time. Rendering algorithms to distinguish different kinds of sets (e.g., GriddedSet, etc). 8. Color RealType to 1-D color component via ScalarMap.function RealType to 3-D color via ColorControl compositing multiple color layers ordered layers a. ordered by Zaxis and using Alpha compositing? b. DataRenderer-s create PixelArray2D & PixelArray3D arrays of color DisplayRenderer composites these by Data object order pan layers by per object XAxisOffset and YAxisOffset ConstantMap Fulker wants consistent color tables across multiple objects McIDAS supports independent color table per frame used for navigation landmark images emulate this on-the-fly via computation 9. Pan / scroll and Zoom (spatial) support very large images can PixelArray2D & PixelArray3D do this? links from UI embedded in Display to ProjectionControl scroll control via scroll bar zoom control via rubberband box re-center via mouse click auto-scale and auto-center 10. Animation animation scroll and zoom divisible real line UI for animationi, link to AnimationControl auto-scale and -center some Data objects animate by scene graph events, some need re-transform 11. Auto scaling spatial axes, animation, color, etc * class java.lang.Object o interface visad.Action (extends java.rmi.Remote) + interface visad.Display (extends visad.Action) + interface visad.RemoteDisplay (extends visad.Display) + interface visad.RemoteAction (extends visad.Action) o class visad.ActionImpl (implements visad.Action, java.lang.Runnable) + class visad.DisplayImpl (implements visad.Display) o class visad.Control (implements Cloneable) + class visad.AnimationControl + class visad.ColorControl + class visad.ContourControl + class visad.FlowControl + class visad.Flow1Control + class visad.Flow2Control + class visad.ProjectionControl + class visad.RangeControl + class visad.ValueControl o class visad.CoordinateSystem (implements Serializable) o interface visad.Data (extends java.rmi.Remote) + interface visad.RemoteData (extends visad.Data) + interface visad.Function (extends visad.Data) + interface visad.RemoteFunction (extends visad.Function) + interface visad.Field (extends visad.Function) + interface visad.RemoteField (extends visad.Field) o class visad.DataChangedOccurrence (implements Serializable) o class visad.DataImpl (implements visad.Data, Cloneable, Serializable) + class visad.FunctionImpl (implements visad.Function) + class visad.FieldImpl (implements visad.Field) + class visad.FlatField + class visad.Scalar + class visad.Real + class visad.Text + class visad.Set + class visad.SimpleSet + class visad.DoubleSet + class visad.FloatSet + class visad.GriddedSet + class visad.Gridded1DSet + class visad.Linear1DSet + class visad.Integer1DSet + class visad.Gridded2DSet + class visad.Linear2DSet + class visad.Integer2DSet + class visad.LinearLatLonSet + class visad.Gridded3DSet + class visad.Linear3DSet + class visad.Integer3DSet + class visad.IrregularSet + class visad.Irregular1DSet + class visad.Irregular2DSet + class visad.Irregular3DSet + class visad.LinearSet + class visad.IntegerSet + class visad.SingletonSet + class visad.Tuple + class visad.RealTuple o interface visad.DataReference (extends java.rmi.Remote) + interface visad.RemoteDataReference (extends visad.DataReference) o class visad.DataReferenceImpl (implements visad.DataReference) o class visad.DateTime (implements Serializable) o class visad.ErrorEstimate (implements Serializable) o class visad.MathType (implements Serializable) + class visad.FunctionType + class visad.ScalarType + class visad.RealType + class visad.DisplayRealType + class visad.TextType + class visad.SetType + class visad.TupleType + class visad.RealTupleType + class visad.DisplayTupleType + class visad.RealVectorType o interface visad.RemoteClientTest (extends java.rmi.Remote) o class java.rmi.server.RemoteObject (implements java.rmi.Remote, Serializable) + class java.rmi.server.RemoteServer + class java.rmi.server.UnicastRemoteObject + class visad.RemoteActionImpl (implements visad.RemoteAction) + class visad.RemoteDisplayImpl (implements visad.RemoteDisplay) + class visad.RemoteClientTestImpl (implements visad.RemoteClientTest) + class visad.RemoteDataImpl (implements visad.RemoteData) + class visad.RemoteFunctionImpl (implements visad.RemoteFunction) + class visad.RemoteFieldImpl (implements visad.RemoteField) + class visad.RemoteDataReferenceImpl (implements visad.RemoteDataReference) + class visad.RemoteServerTestImpl (implements visad.RemoteServerTest) o interface visad.RemoteServerTest (extends java.rmi.Remote) o class visad.Renderable o class visad.Renderer o class visad.ScalarMap (implements Serializable) + class visad.ConstantMap o class visad.ShadowType + class visad.ShadowFunctionType + class visad.ShadowRealType + class visad.ShadowSetType + class visad.ShadowTextType + class visad.ShadowTupleType + class visad.ShadowRealTupleType o class java.lang.Throwable (implements Serializable) + class java.lang.Error + class visad.VisADError + class java.lang.Exception + class visad.VisADException + class visad.CoordinateSystemException + class visad.DisplayException + class visad.BadMappingException + class visad.FieldException + class visad.ReferenceException + class visad.RemoteVisADException + class visad.SetException + class visad.TypeException + class visad.UnimplementedException + class visad.UnitException o class visad.Unit (implements Serializable)