001: /*
002: * $RCSfile: DeferredData.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:57:07 $
010: * $State: Exp $
011: */
012: package javax.media.jai;
013:
014: import java.io.Serializable;
015: import java.util.Observable;
016:
017: /**
018: * Class to be used as a wrapper for data which will be calculated
019: * at a later time. For example, an instance of a subclass of this
020: * class may be passed as a parameter in the <code>ParameterBlock</code>
021: * set on a <code>RenderedOp</code> node. The data wrapped by the
022: * <code>DeferredData</code> object will not however actually be
023: * requested until the node is rendered.
024: *
025: * @see DeferredProperty
026: * @see RenderedOp
027: *
028: * @since JAI 1.1
029: */
030: public abstract class DeferredData extends Observable implements
031: Serializable {
032: /**
033: * The class of the wrapped data.
034: */
035: protected Class dataClass;
036:
037: /**
038: * The data wrapped by this class. This field is marked
039: * <code>transient</code> so that subclasses are obligated to provide
040: * specific serialization methods if they desire that this field be
041: * serialized.
042: */
043: protected transient Object data;
044:
045: /**
046: * Creates a <code>DeferredData</code> wrapper for an object of the
047: * indicated class. The parameter must be non-<code>null</code> or an
048: * <code>IllegalArgumentException</code> will be thrown.
049: *
050: * @throws IllegalArgumentException if <code>dataClass</code> is
051: * <code>null</code>.
052: */
053: protected DeferredData(Class dataClass) {
054: if (dataClass == null) {
055: throw new IllegalArgumentException(JaiI18N
056: .getString("DeferredData0"));
057: }
058: this .dataClass = dataClass;
059: }
060:
061: /**
062: * Returns the class of the object wrapped by this DeferredData.
063: */
064: public Class getDataClass() {
065: return dataClass;
066: }
067:
068: /**
069: * Whether the data value has already been computed.
070: *
071: * @return <code>true</code> if and inly if the internal data value is
072: * non-<code>null</code>, i.e., has already been computed.
073: */
074: public boolean isValid() {
075: return data != null;
076: }
077:
078: /**
079: * Computes the value of the data object wrapped by this object.
080: * The returned object must be an instance of a class assignable
081: * to the class specified at construction.
082: */
083: protected abstract Object computeData();
084:
085: /**
086: * Returns the object wrapped by this <code>DeferredData</code>. If
087: * the data have not yet been computed, <code>computeData()</code>
088: * will be invoked to provide the data. If <code>computeData()</code>
089: * is invoked, then <code>setData()</code> will be invoked with
090: * its parameter set to the value returned by <code>computeData()</code>.
091: */
092: public synchronized final Object getData() {
093: if (data == null) {
094: setData(computeData());
095: }
096: return data;
097: }
098:
099: /**
100: * Sets the instance variable associated with the data to the supplied
101: * parameter. If the parameter is non-<code>null</code> and not an
102: * instance of the class specified at construction, an
103: * <code>IllegalArgumentException</code> will be thrown. If the
104: * supplied parameter differs from the current data value, then
105: * <code>setChanged()</code> will be invoked and
106: * <code>notifyObservers()</code> will be called with its argument set
107: * to the previous value of the data object. This implies that the
108: * <code>update()</code> method of any registered <code>Observer</code>s
109: * will be invoked with the <code>Observable</code> parameter set to this
110: * <code>DeferredData</code> object and its <code>Object</code> parameter
111: * set to the previous value of the <code>data</code> field of this
112: * <code>DeferredData</code> instance. The current value of the
113: * object can be retrieved by an <code>Observer</code> by casting the
114: * <code>Observable</code> parameter of <code>update()</code> to
115: * <code>DeferredData</code> and invoking <code>getData()</code>. To
116: * avoid provoking computation of deferred data by calling
117: * <code>getData()</code>, <code>isValid()</code> could first be called
118: * to determine whether <code>data</code> is non-<code>null</code>.
119: * If an <code>Observer</code> detects that the data of the observed
120: * <code>DeferredData</code> object is invalid, i.e., <code>null</code>,
121: * then this indicates that the data should be re-requested by invoking
122: * <code>getData()</code>.
123: *
124: * @throws IllegalArgumentException if <code>data</code> is
125: * non-<code>null</code> and not an instance of the class
126: * specified at construction.
127: */
128: protected final void setData(Object data) {
129: if (data != null && !dataClass.isInstance(data)) {
130: throw new IllegalArgumentException(JaiI18N
131: .getString("DeferredData1"));
132: }
133: if (this .data == null || !this .data.equals(data)) {
134: Object oldData = this.data;
135: this.data = data;
136: setChanged();
137: notifyObservers(oldData);
138: }
139: }
140: }
|