@(#)Property.txt 1.11 Proposal: Improved Property Management ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Brian Burkhalter Created: 13 July 2000 Revised: 12/18/00 CHANGES DURING COMMUNITY REVIEW ------------------------------- . Added specification of PropertyChangeSupportJAI class. PROPOSAL -------- 1. Motivation This proposal arises in response to sundry requests for various changes to the property management API provided in the first version of the JAI API specification. In particular the following areas are of concern: Retention of Property Name Case The case of property names is not maintained by the API which may lead to some confusion and loss of clarity and aesthetics. Property Synchronization Unlike image data the property data attached to an image rendered from a node in an operation chain may change spontaneously after the rendering has been generated. Multiple Property Name Spaces Only a single name space is provided for property names. This is perceived as a limitation due to problems which could could arise from property name collisions. Property Specification Clarification Some aspects of the API specification for property management are unclear. Following the next section each of these topics is addressed in the order listed. The use of the term "properties" in JAI could cause easily be confused with properties as used with Java Beans. Properties of Java Beans are configurable attributes of objects which are made available to adaptive code via introspection. Properties in JAI usually represent meta-data of an image such as regions of interest, coordinate systems, etc. In this proposal the use of Java Bean type properties is added to JAI image classes and JAI properties are linked into the Java Beans property model. 2. Fundamental Modifications 2.1 Java Bean-style Events 2.1.1 Define a Bean Event Base Class Define to be used as the base class for all bean-style events generated by JAI image objects. package javax.media.jai; import java.beans.PropertyChangeEvent; /** * A class instances of which represent Java Bean-style events emitted by * JAI objects. This class definition adds no functionality to that provided * by the superclass. The significance of the derivation is that bean events * will be easily identifiable as having been generated by JAI classes by * virtue of their being instances of this event class. Note that this does * not prevent JAI properties from colliding with other Java Bean properties * in the Bean property name space. * * @since Java Advanced Imaging 1.1 */ public class PropertyChangeEventJAI extends PropertyChangeEvent { /** * Constructs a PropertyChangeEventJAI. * propertyName is forced to lower case; all other * parameters are passed unmodified to the superclass constructor. * The original property name may be obtained by invoking * getOriginalPropertyName(). * * @exception NullPointerException if propertyName is * null. * @exception IllegalArgumentException if source is * null or if oldValue and * newValue are both null. */ public PropertyChangeEventJAI(Object source, String propertyName, Object oldValue, Object newValue) {} /** * Returns the value of propertyName originally passed to * the class constructor. This name has its case retained. */ public String getOriginalPropertyName() {} } Also define a utility class which forces property names to lower case and allows retrieval of the property change event source: /** * Extension of the beans utility class PropertyChangeSupport * which adds an accessor for the parameter passed to the constructor. All * events fired by the firePropertyChange() methods of this * class are instances of PropertyChangeEventJAI; consequently * all property names are forced to lower case for recognition purposes. * The property name-specific PropertyChangeListener registration * and unregistration methods defined in this class also force the supplied * property name to lower case. * * @see PropertyChangeSupport * * @since 1.1 */ public final class PropertyChangeSupportJAI extends PropertyChangeSupport { /** * The PropertyChangeEvent source. */ protected Object propertyChangeEventSource; /** * Constructs a PropertyChangeSupportJAI object. The * parameter is cached for later use and retrieval. * * @param propertyChangeEventSource The property change event source. * @throws If propertyChangeEventSource is null * then a NullPointerException will be thrown * in the superclass. */ public PropertyChangeSupportJAI(Object propertyChangeEventSource) {} /** * Retrieve the parameter passed to the constructor. * * @return The property change event source. */ public Object getPropertyChangeEventSource() {} /** * Add a PropertyChangeListener for a specific property. * The propertyName is forced to lower case. * * @exception IllegalArgumentException if propertyName is * null. */ public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {} /** * Remove a PropertyChangeListener for a specific property. * The propertyName is forced to lower case. * * @exception IllegalArgumentException if propertyName is * null. */ public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {} /** * Report a bound property update to any registered listeners. * If the supplied object is not a PropertyChangeEventJAI * then a PropertyChangeEventJAI is constructed from the * event object's accessors and fired instead. * * @param evt The PropertyChangeEvent object. */ public void firePropertyChange(PropertyChangeEvent evt) {} /** * Report a bound property update to any registered listeners. * A PropertyChangeEventJAI is created from the cached * property event source and the supplied parameters and fired using * the superclass firePropertyChange(PropertyChangeEvent) * method. * * @param propertyName The name of the changed property. * @param oldValue The old value of the property. * @param newValue The new value of the property. */ public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {} /** * Check whether there are any listeners for a specific property. * The propertyName is forced to lower case. * * @param propertyName The name of the property. * @return true if there are one or more listeners for * the given property */ public synchronized boolean hasListeners(String propertyName) {} } 2.1.2 Define a Class Linking JAI Properties and Java Beans Properties Properties as defined in the context of Java Beans and as defined in JAI are two entirely different entities. This class provides a construct linking the two concepts. package javax.media.jai; /** * A class instances of which represent JAI properties as emitted for * example by a PropertySource but in the guise of an event * as defined for Java Beans. This class definition adds no functionality * to that provided by the superclass per se. The significance of the * derivation is that instances of this event by definition refer to properties * in the JAI sense of the term. Otherwise put, this class provides an extra * level of indirection. * * @see PropertyChangeEventJAI * @see PropertySource * * @since Java Advanced Imaging 1.1 */ public class PropertySourceChangeEvent extends PropertyChangeEventJAI { /** * Constructs a PropertySourceChangeEvent. * propertyName is forced to lower case; all other * parameters are passed unmodified to the superclass constructor. * If oldValue or newValue is to indicate * a property for which no value is defined, then the object * java.awt.Image.UndefinedProperty should be passed. * * @exception NullPointerException if propertyName is * null. * @exception IllegalArgumentException if source, * oldValue or newValue is * null. */ public PropertySourceChangeEvent(Object source, String propertyName, Object oldValue, Object newValue) {} } 2.2 Define an Interface for PropertyChangeListener Registration /** * A class which emits PropertyChangeEvents. * This abstraction permits objects of disparate types to be recognized * as sources of PropertyChangeEvents. * PropertyChangeEvents emitted by JAI objects will be * PropertyChangeEventJAI instances. * *

Note that the case of property names used in this context is * significant. * * @see PropertyChangeEventJAI * * @since Java Advanced Imaging 1.1 */ public interface PropertyChangeEmitter { /** * Add a PropertyChangeListener to the listener list. The * listener is registered for all properties. */ void addPropertyChangeListener(PropertyChangeListener listener); /** * Add a PropertyChangeListener for a specific property. The * listener will be invoked only when a call on * firePropertyChange names that specific property. */ void addPropertyChangeListener(String propertyName, PropertyChangeListener listener); /** * Remove a PropertyChangeListener from the listener list. This * removes a PropertyChangeListener that was registered for all * properties. */ void removePropertyChangeListener(PropertyChangeListener listener); /** * Remove a PropertyChangeListener for a specific property. */ void removePropertyChangeListener(String propertyName, PropertyChangeListener listener); } 2.3 Modify PropertySource Interface Specification 2.3.1 Add comments to the class specification: *

If a PropertySource is also a * PropertyChangeEmitter * then it should fire PropertySourceChangeEvents to all * registered listeners whenever this is reasonable to do so in the context * of the PropertySource in question. 2.3.2 Add a method specification: /** * Returns the class expected to be returned by a request for * the property with the specified name. If this information * is unavailable, null will be returned indicating * that getProperty(propertyName).getClass() should * be executed instead. A null value might * be returned for example to prevent generating the value of * a deferred property solely to obtain its class. null * will also be returned if the requested property is not emitted * by this property source. * * @param propertyName the name of the property, as a String. * * @return The Class expected to be return by a * request for the value of this property or null. * * @exception IllegalArgumentException if propertyName * is null. */ Class getPropertyClass(String propertyName); This method may help in identifying the names of properties which return values which are instances of a specific class. All classes which implement PropertySource or ImageJAI will be modified to implement this method. 2.4 Modify PropertyGenerator Interface Specification Addition of the following methods enables the generic interface to accomodate as yet unidentified operation node types or other objects for which properties may be generated. All classes which implement or which use classes which implement this interace will need to be modified accordingly. 2.4.1 Add Verifier /** * Determines whether the specified Object will * be recognized by getProperty(String,Object). * * @exception IllegalArgumentException if opNode * is null. */ boolean canGenerateProperties(Object opNode); 2.4.2 Add Property Class Accessor /** * Returns the class expected to be returned by a request for * the property with the specified name. If this information * is unavailable, null will be returned indicating * that getProperty(propertyName).getClass() should * be executed instead. A null value might * be returned for example to prevent generating the value of * a deferred property solely to obtain its class. * * @return The Class expected to be return by a * request for the value of this property or null. * @exception IllegalArgumentException if propertyName * is null. */ Class getClass(String propertyName); 2.4.3 Add a Generic Property Accessor /** * Computes the value of a property relative to an environment * of pre-existing properties. The case of the supplied * String is ignored. * *

In the case of an OperationNode in a chain of * operations these properties may be emitted by the sources of the * node in a chain or the parameters of that operation. The information * requisite to compute the requested property must be available via the * supplied OperationNode. It is legal to call * getProperty() on the operation's sources. * * @param name the name of the property, as a String. * @param op the Object from which properties will * be generated. * @return the value of the property, as an Object or the * value java.awt.Image.UndefinedProperty. * @exception IllegalArgumentException if name or * opNode is null. * @exception IllegalArgumentException if opNode is * not an instance of a supported class for this method, i.e., * canGenerateProperties(opNode) returns * false. */ Object getProperty(String name, Object opNode); The getProperty() methods which accept a RenderedOp or a RenderableOp as the second parameter are deprecated as they will be redundant with the above. 2.5 Create WritablePropertySource Sub-Interface Create a sub-interface of PropertySource in javax.media.jai: /** * Sub-interface of PropertySource which permits setting * the values of JAI properties in addition to obtaining their names * and values. As the values of properties managed by classes which * implement this interface may change, this is also a sub-interface * of PropertyChangeEmitter. This permits other objects * to register as listeners of particular JAI properties. * *

The case of the names of properties added via this interface * should be retained although the case will be ignored in queries via * getProperty() and will be forced to lower case in * emitted PropertySourceChangeEvent. * * @see PropertySource * @see PropertyChangeEmitter * * @since Java Advanced Imaging 1.1 */ public interface WritablePropertySource extends PropertySource, PropertyChangeEmitter {} This sub-interface would add the following methods: /** * Adds the property value associated with the supplied name to * the WritablePropertySource. Properties set by * this means will supersede any properties of the same name * which might otherwise be derived dynamically. * *

Implementing classes which should * fire a PropertySourceChangeEvent with a name set to * that of the set property (retaining case), source set to the * WritablePropertySource, and old and new values set to * the previous and current values of the property, respectively. * Neither the old nor the new value may null: undefined * properties must as usual be indicated by an the constant value * java.awt.Image.UndefinedProperty. It is however * legal for either but not both of the old and new property values * to equal java.awt.Image.UndefinedProperty. * * @param propertyName the name of the property, as a String. * @param propertyValue the property, as a general Object. * * @exception IllegalArgumentException if propertyName * or propertyValue * is null. */ void setProperty(String propertyName, Object propertyValue); /** * Removes the named property from the WritablePropertySource. * This method will clear any locally cached (static) properties * but may have no effect on properties which would be derived * dynamically. * * @param propertyName the name of the property, as a String. * @param propertyValue the property, as a general Object. * * @exception IllegalArgumentException if propertyName * is null. */ void removeProperty(String propertyName); 2.6 Implement PropertySource Create a utility implementation of PropertySource. Note that the extant package scope class of the same name will have to be renamed, e.g., to "PropertyEnvironment". 2.6.1 Create a Utility Class for Property Name Handling package javax.media.jai.util; /** * Class to use as the key in a java.util.Map. * The case of the name is maintained but the equals() * method performs case-insensitive comparison. * * @see PropertySource * @see java.util.Map * * @since Java Advanced Imaging 1.1 */ public final class CaselessStringKey implements Cloneable, Serializable { /** * Creates a CaselessStringKey for the given name. * The parameter name is stored by reference. * * @throws IllegalArgumentException if name is * null. */ public CaselessStringKey(String name) {} /** * Returns a hash code value for the CaselessStringKey. */ public int hashCode() {} /** * Returns the internal name by reference. */ public String getName() {} /** * Stores the parameter by reference in the internal name. * * @throws IllegalArgumentException if name is * null. */ public void setName(String name) {} /** * Returns a clone of the CaselessStringKey as an * Object. */ public Object clone() {} /** * Whether another Object equals this one. This will obtain * if and only if the parameter is non-null and is a * CaselessStringKey whose lower case name equals the * lower case name of this CaselessStringKey. */ public boolean equals(Object o) {} /** * Returns the value returned by getName(). */ public String toString() {} } 2.6.2 Class Definition package javax.media.jai; import java.util.Map; /** * A utility implementation of the PropertySource interface. * Properties are managed by three internal structures: one which maps * property names to values, a second which maps property names to * PropertySources, and a third which tracks which entries * in the name-value mapping derived their respective values from a * PropertySource in the name-PropertySource * mapping. The case of property names is retained for subsequent * retrieval but is ignored when the names are used as keys. * * @see CaselessStringKey * @see PropertySource * @see PropertySourceImpl * @see WritablePropertySource * @see WritablePropertySourceImpl * * @since Java Advanced Imaging 1.1 */ public class PropertySourceImpl implements PropertySource, Serializable { /** * Mapping of CaselessStringKeys to values. * If this object is serialized, only those entries of which * the value is serializable will be retained. */ protected transient Map properties; /** * Mapping of CaselessStringKeys to * PropertySources. * If this object is serialized, only those entries of which * the value is serializable will be retained. */ protected transient Map propertySources; /** * CaselessStringKeys corresponding to the keys of entries * in properties which derived their respective * values from a PropertySource in * propertySources. */ protected Set cachedPropertyNames; /** * Constructs a PropertySourceImpl instance with * no properties set. */ protected PropertySourceImpl() {} /** * Constructs a PropertySourceImpl instance which * will derive properties from one or both of the supplied parameters. * The propertyMap and propertySource parameters * will be used to initialize the name-value and * name-PropertySource mappings, respectively. * Entries in the propertyMap object will be assumed * to be properties if the key is a String or a * CaselessStringKey. The propertySource * object will be queried for the names of properties that it emits * but requests for associated values will not be made at this time * so as to to defer any calculation that such requests might provoke. * The case of property names will be retained but will be ignored * insofar as the name is used as a key to the property value. * * @param propertyMap A Map from which to copy properties * which have keys which are either Strings or * CaselessStringKeys. * @param propertySource A PropertySource from which to * derive properties. * * @exception IllegalArgumentException if propertyMap * and propertySource are both null * and this constructor is not being invoked from within a * subclass constructor. When invoked from a subclass * constructor both parameters may be null. */ public PropertySourceImpl(Map propertyMap, PropertySource propertySource) {} 2.6.3 Add Convenience Method /** * Copies into a Map all properties currently available * via this PropertySource. All property values are * copied by reference rather than by being cloned. The keys in the * Map will be Strings with the original * property name case intact. Property values derived from the * name-value mapping will take precedence. The names of properties * whose values are derived via the name-PropertySource * mapping will be recorded as "cached properties". * * @return A Map of all properties or null if * none are defined. */ public Map getProperties() {} 2.7 Implement WritablePropertySource Create a utility implementation of WritablePropertySource. This implementation will be synchronized and retain the case of all property names. 2.7.1 Class Definition /** * A utility implementation of the WritablePropertySource * interface. The same internal superclass data structures are used and * are supplemented by a PropertyChangeSupportJAI to handle * property event firing. All events fired by an instance of this class * will be PropertySourceChangeEvents with an event source * equal to the object used to create the PropertyChangeSupportJAI * helper object. This object is user-specifiable at construction time or * automatically created when a PropertyChangeListener is * added or removed and the PropertyChangeSupportJAI specified * at construction was null. * * @see CaselessStringKey * @see PropertySource * @see PropertySourceChangeEvent * @see PropertySourceImpl * @see WritablePropertySource * @see PropertyChangeEmitter * @see PropertyChangeSupportJAI * * @since Java Advanced Imaging 1.1 */ public class WritablePropertySourceImpl extends PropertySourceImpl implements WritablePropertySource { /** * Helper object for bean-style property events. Its default * value is null which indicates that no events * are to be fired. */ protected PropertyChangeSupportJAI manager = null; /** * Constructs a WritablePropertySourceImpl instance with * no properties set. */ public WritablePropertySourceImpl() { super(); } /** * Constructs a WritablePropertySourceImpl instance which * will derive properties from one or both of the supplied parameters. * The propertyMap and propertySource parameters * will be used to initialize the name-value and * name-PropertySource mappings, respectively. * Entries in the propertyMap object will be assumed * to be properties if the key is a String or a * CaselessStringKey. The propertySource * object will be queried for the names of properties that it emits * but requests for associated values will not be made at this time * so as to to defer any calculation that such requests might provoke. * The case of property names will be retained but will be ignored * insofar as the name is used as a key to the property value. * * @param propertyMap A Map from which to copy properties * which have keys which are either Strings or * CaselessStringKeys. * @param propertySource A PropertySource from which to * derive properties. * @param manager The object which will actually fire the events. * May be null in which case a default * event manager will be created as needed with this * object as its event source. */ public WritablePropertySourceImpl(Map propertyMap, PropertySource source, PropertyChangeSupportJAI manager) {} 2.7.2 Add Convenience Methods Add these methods which are not defined in the interface: /** * Copies from the supplied Map to the property set all * entries wherein the key is an instance of String * or CaselessStringKey. Values set by this means will * supersede any previously defined values of the respective properties. * All property values are copied by reference. * PropertySourceChangeEvents may be fired for each * property added. If the property was not previously defined the * old value of the property event will be * java.awt.Image.UndefinedProperty. * * @param propertyMap A Map from which to copy properties * which have keys which are either Strings or * CaselessStringKeys. If null no * properties will be added. */ public void addProperties(Map propertyMap) {} /** * Adds a PropertySource to the * name-PropertySource mapping. The * actual property values are not requested at this time but instead * an entry for the name of each property emitted by the * PropertySource is added to the * name-PropertySource mapping. Properties defined by * this PropertySource supersede those of all other * previously added PropertySources including that * specified at construction, if any. Note that this method will not * provoke any events as no properties will actually have changed. * * @param propertySource A PropertySource from which to * derive properties. If null nothing is done. */ public void addProperties(PropertySource propertySource) {} /** * Clears all properties from the PropertySource by * invoking removeProperty() with all known names. * PropertySourceChangeEvents may be fired * for each stored property removed. In this case the new value * of the property event will be * java.awt.Image.UndefinedProperty. */ public void clearProperties() {} /** * Clears the name-value mapping of all properties. * PropertySourceChangeEvents may be fired * for each stored property removed. In this case the new value * of the property event will be * java.awt.Image.UndefinedProperty. */ public void clearPropertyMap() {} /** * Clears the name-PropertySource mapping. * No events will be fired. */ public void clearPropertySourceMap() {} /** * Clears from the name-value mapping all properties which were * derived from a source in the name-PropertySource mapping. * PropertySourceChangeEvents may be fired * for each stored property removed. In this case the new value * of the property event will be * java.awt.Image.UndefinedProperty. */ public void clearCachedProperties() {} /** * Removes from the name-PropertySource mapping all entries * which refer to the supplied PropertySource. */ public void removePropertySource(PropertySource propertySource) {} 2.7.3 Add PropertyChangeEmitter Methods /** * Add a PropertyChangeListener to the listener list. The * listener is registered for all properties. * *

If the property event utility object was not set at construction, * then it will be initialized to a PropertyChangeSupportJAI * whose property event source is this object. */ public void addPropertyChangeListener(PropertyChangeListener listener) {} /** * Add a PropertyChangeListener for a specific property. The * listener will be invoked only when a call on * firePropertyChange names that specific property. * *

If the property event utility object was not set at construction, * then it will be initialized to a PropertyChangeSupportJAI * whose property event source is this object. */ public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {} /** * Remove a PropertyChangeListener from the listener list. * This removes a PropertyChangeListener that was registered * for all properties. * *

If the property event utility object was not set at construction, * then it will be initialized to a PropertyChangeSupportJAI * whose property event source is this object. */ public void removePropertyChangeListener(PropertyChangeListener listener) {} /** * Remove a PropertyChangeListener for a specific property. * *

If the property event utility object was not set at construction, * then it will be initialized to a PropertyChangeSupportJAI * whose property event source is this object. */ public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {} 2.8 Define an Interface Representing Generic Operation Nodes While this modification is more of a generic change to the core architecture it is presented in the context of this proposal nonetheless. 2.8.1 OperationNode Interface Specification /** * A class which is a node in a chain of operations. This interface * aggregates the minimal set of methods which would be expected to be * implemented by such a class. * *

Accessors and mutators of the critical attributes of the node * are provided: * *

* * Whether an implementing class maintains these critical attributes by * reference or by copying or cloning is left to the discretion of the * implementation. * *

OperationNodes should fire a * PropertyChangeEventJAI when any of the critical attributes of * the node is modified. These events should be named "OperationName", * "OperationRegistry", "ParameterBlock", and "RenderingHints" corresponding * to the respective critical attributes. Events named "Sources" and * "Parameters" may instead be fired if it can be determined that a * ParameterBlock modification has affected only the sources * or parameters of the node, respectively. Nodes which implement convenience * methods to edit individual node sources, parameters, or hints should * still fire an event for the attribute as a whole. Note that this might * require cloning the respective object. OperationNodes are * also required to fire PropertySourceChangeEvents by virtue * of their being a PropertySource as well as a * PropertyChangeEmitter. * *

Methods are also provided to modify the local property environment * of the node. The global property environment is maintained by the * associated OperationRegistry and used to initialize the * local property environment. Methods are provided to: * *

* * Invocation of these methods would not affect the global property * environment of the operation as maintained by the * OperationRegistry. */ public interface OperationNode extends PropertySource, PropertyChangeEmitter { /** * Returns the name of the RegistryMode corresponding to * this OperationNode. This value should be immutable * for a given node. */ String getRegistryModeName(); /** * Returns the name of the operation this node represents as * a String. */ String getOperationName(); /** * Sets the name of the operation this node represents. * *

A PropertyChangeEventJAI named "OperationName" * should be fired with * source equal to this node and old and new values set to the old * and new values of the operation name, respectively. * * @param opName The new operation name to be set. * * @throws NullPointerException if opName is * null. */ void setOperationName(String opName); /** * Returns the OperationRegistry that is used * by this node. If the registry is not set, the default * registry is returned. */ OperationRegistry getRegistry(); /** * Sets the OperationRegistry that is used by * this node. If the specified registry is null, the * default registry is used. * *

A PropertyChangeEventJAI named "OperationRegistry" * should be fired with * source equal to this node and old and new values set to the old * and new values of the registry, respectively. * * @param registry The new OperationRegistry to be set; * it may be null. */ void setRegistry(OperationRegistry registry); /** * Returns the ParameterBlock of this node. */ ParameterBlock getParameterBlock(); /** * Sets the ParameterBlock of this node. If the specified * new ParameterBlock is null, it is assumed * that this node has no input sources and parameters. * *

This method does not validate the content of the supplied * ParameterBlock. The caller should ensure that * the sources and parameters in the ParameterBlock * are suitable for the operation this node represents; otherwise * some form of error or exception may occur at the time of rendering. * *

A PropertyChangeEventJAI named "ParameterBlock" * should be fired with * source equal to this node and old and new values set to the old * and new values of the ParameterBlock, respectively. * A PropertyChangeEventJAI named "Sources" or * "Parameters" may instead be fired if it can be determined that the * ParameterBlock modification has affected only the sources * or parameters of the node, respectively. * * @param pb The new ParameterBlock to be set; * it may be null. */ void setParameterBlock(ParameterBlock pb); /** * Returns the RenderingHints of this node. * It may be null. */ RenderingHints getRenderingHints(); /** * Sets the RenderingHints of this node. It is legal * for nodes to ignore RenderingHints set on them by * this mechanism. * *

A PropertyChangeEventJAI named "RenderingHints" * should be fired with * source equal to this node and old and new values set to the old * and new values of the hints, respectively. * * @param hints The new RenderingHints to be set; * it may be null. */ void setRenderingHints(RenderingHints hints); /** * Returns the property associated with the specified property name, * or java.awt.Image.UndefinedProperty if the specified * property is not set on the image. This method is dynamic in the * sense that subsequent invocations of this method on the same object * may return different values as a function of changes in the property * environment of the node, e.g., a change in which * PropertyGenerators are registered or in the values * associated with properties of node sources. The case of the property * name passed to this method is ignored. * * @param name A String naming the property. * * @throws IllegalArgumentException if * name is null. */ Object getDynamicProperty(String name); /** * Adds a PropertyGenerator to the node. The property values * emitted by this property generator override any previous * definitions. * * @param pg A PropertyGenerator to be added to this node's * property environment. * * @throws IllegalArgumentException if * pg is null. */ void addPropertyGenerator(PropertyGenerator pg); /** * Forces a property to be copied from the specified source node. * By default, a property is copied from the first source node * that emits it. The result of specifying an invalid source is * undefined. * * @param propertyName the name of the property to be copied. * @param sourceIndex the index of the from which to copy the property. * @throws IllegalArgumentException if propertyName is * null. */ void copyPropertyFromSource(String propertyName, int sourceIndex); /** * Removes a named property from the property environment of this * node. Unless the property is stored locally either due * to having been set explicitly or to having been cached for property * synchronization purposes, subsequent calls to * getProperty(name) will return * java.awt.Image.UndefinedProperty, and name * will not appear on the list of properties emitted by * getPropertyNames(). * * @param name A String naming the property to be suppressed. * * @throws IllegalArgumentException if * name is null. */ void suppressProperty(String name); } 2.8.2 OperationNode Utility Class Specification /** * This is a utility class that can be used by OperationNodes * to consolidate common functionality. An instance of this class may be * used as a member field of the OperationNode and some of the * OperationNode's work delegated to it. */ public class OperationNodeSupport implements Serializable { /** * Constructs an OperationNodeSupport instance. * All parameters except opName may be null. * If non-null the PropertyChangeSupportJAI * should have been created with the node as its event source (note * that this cannot be verified). * * @param registryModeName The name of the registry mode concerned. * @param opName The operation name to set. * @param registry The OperationRegistry to set; * it may be null in which case the registry will * will be set to the default JAI registry. * @param pb The ParameterBlock to set; * it may be null. * @param hints The new RenderingHints to be set; * it may be null. * @param eventManager The event helper object. The property change * event source of this object should be the * OperationNode which is using the constructed * OperationNodeSupport instance. If null * no events will be fired. * * @throws IllegalArgumentException if opName is * null. */ public OperationNodeSupport(String registryModeName, String opName, OperationRegistry registry, ParameterBlock pb, RenderingHints hints, PropertyChangeSupportJAI eventManager) {} /** * Returns the name of RegistryMode corresponding to * this OperationNode. This value shoud be immutable * for a given node. The value is returned by reference. */ public String getRegistryModeName() {} /** * Returns the name of the operation the associated node represents. * The value is returned by reference. */ public String getOperationName() {} /** * Sets the name of the operation the associated node represents. * The value is set by reference. * *

If the operation name changes as a result of calling this * method, a PropertyChangeEventJAI named "OperationName" * will be fired by the event helper object with old and new values * set to the old and new values of the operation name, respectively. * * @param opName The new operation name to be set. * * @throws IllegalArgumentException if opName is * null. */ public void setOperationName(String opName) {} /** * Returns the OperationRegistry used by the associated * node. The value is returned by reference. */ public OperationRegistry getRegistry() {} /** * Sets the OperationRegistry that is used by the associated * node. If the specified registry is null, the * registry will be set to the default JAI registry. The value is * set by reference. * *

If the registry changes as a result of calling this * method, a PropertyChangeEventJAI named "OperationRegistry" * will be fired by the event helper object with old and new values * set to the old and new values of the registry, respectively. * * @param registry The new OperationRegistry to be set; * it may be null. */ public void setRegistry(OperationRegistry registry) {} /** * Returns the ParameterBlock of the associated node * by reference. Nodes desirous of maintaining a consistent state * for their ParameterBlock may prefer to clone the * value returned by this method. */ public ParameterBlock getParameterBlock() {} /** * Sets the ParameterBlock of the associated node by * reference. If the specified ParameterBlock is * null, it is assumed that the associated node has * neither input sources nor parameters. Nodes desirous of maintaining * a consistent state for their ParameterBlock may prefer * to clone any user-supplied ParameterBlock before passing * it to this method. * *

This method does not validate the content of the supplied * ParameterBlock. The caller should ensure that * the sources and parameters in the ParameterBlock * are suitable for the operation the associated node represents; otherwise * some form of error or exception may occur at the time of rendering. * *

If the ParameterBlock changes as a result of calling * this method, a PropertyChangeEventJAI named "ParameterBlock" * will be fired by the event helper object with old and new values * set to the old and new values of the ParameterBlock, * respectively. A PropertyChangeEventJAI named "Sources" or * "Parameters" will instead be fired if it can be determined that the * ParameterBlock modification has affected only the sources * or parameters of the node, respectively. * * @param pb The new ParameterBlock to be set; * it may be null. */ public void setParameterBlock(ParameterBlock pb) {} /** * Returns the RenderingHints of the associated node * by reference. Nodes desirous of maintaining a consistent state * for their RenderingHints may prefer to clone the * value returned by this method. */ public RenderingHints getRenderingHints() {} /** * Sets the RenderingHints of the associated node. It is * legal for nodes to ignore RenderingHints set on them by * this mechanism. Nodes desirous of maintaining * a consistent state for their RenderingHints may prefer * to clone any user-supplied RenderingHints before passing * it to this method. * *

If the RenderingHints changes as a result of calling * this method, a PropertyChangeEventJAI named "RenderingHints" * will be fired by the event helper object with old and new values * set to the old and new values of the RenderingHints, * respectively. * * @param hints The new RenderingHints to be set; * it may be null. */ public void setRenderingHints(RenderingHints hints) {} /** * Adds a PropertyGenerator to the node. The property values * emitted by this property generator override any previous definitions. * * @param pg A PropertyGenerator to be added to the * associated node's property environment. * * @throws IllegalArgumentException if * pg is null. */ public void addPropertyGenerator(PropertyGenerator pg) {} if(equals(this.hints, hints)) { return; } fireEvent("RenderingHints", this.hints, hints); this.hints = hints; resetPropertyEnvironment(false); } /** * Forces a property to be copied from the specified source node. * By default, a property is copied from the first source node that * that emits it. The result of specifying an invalid source is * undefined. * * @param propertyName the name of the property to be copied. * @param sourceIndex the index of the source to copy the property from. * @throws IllegalArgumentException if propertyName is null. */ public void copyPropertyFromSource(String propertyName, int sourceIndex) {} if(equals(this.hints, hints)) { return; } fireEvent("RenderingHints", this.hints, hints); this.hints = hints; resetPropertyEnvironment(false); } /** * Removes a named property from the property environment of the * associated node. Unless the property is stored locally either due * to having been set explicitly or to having been cached for property * synchronization purposes, subsequent calls to * getProperty(name) will return * java.awt.Image.UndefinedProperty, and name * will not appear on the list of properties emitted by * getPropertyNames(). * * @param name A String naming the property to be suppressed. * * @throws IllegalArgumentException if * name is null. */ public void suppressProperty(String name) {} if(equals(this.hints, hints)) { return; } fireEvent("RenderingHints", this.hints, hints); this.hints = hints; resetPropertyEnvironment(false); } /** * Constructs and returns a PropertySource suitable for * use by the specified OperationNode. The * PropertySource includes the global property environment * as managed by the OperationRegistry for the * corresponding operation. Prior and subsequent modifications to the * local property environment made via this object will be reflected * in the returned PropertySource. * * @param op the OperationNode requesting its * PropertySource. * @param defaultPS a PropertySource to be used to derive * property values if and only if they would otherwise be * derived by inheritance from a source rather than from a * a PropertyGenerator or a copy-from-source * directive. * @throws NullPointerException if op is null. */ public PropertySource getPropertySource(OperationNode opNode, PropertySource defaultPS) {} /** * Resets the property environment. The list of local property * environment modifications made directly on this object is reset * if and only if the parameter is true. * * @param resetLocalEnvironment Whether to clear the list of property * environment changes made directly on this object. */ public void resetPropertyEnvironment(boolean resetLocalEnvironment) {} } 2.9 ImageJAI Modify the definition of ImageJAI to extend WritablePropertySource instead of PropertySource. All classes which implement ImageJAI will have to add the new methods defined for WritablePropertySource. These will be discussed later but include PlanarImage, CollectionImage, and ImageMIPMap. (The classes RenderableOp, MultiResolutionRenderableImage, and RenderableImageAdapter should also be made to implement WritablePropertySource.) 2.9 Rendered Class Modifications 2.9.1 PlanarImage 2.9.1.1 Change Class Defnition Implement WritablePropertySource in addition to the other interfaces. 2.9.1.2 Conform to WritablePropertySource Specification * Implement getClass(name). * Change setProperty() to return a boolean value. (This should have no effect on API users as it previously returned nothing, i.e., was void.) * Implement removeProperty(). * Modify internals of getProperties() and setProperties(). 2.9.1.3 Improve Property Encapsulation The instance variable protected Hashtable properties; will be replaced with a protected instance variable to handle properties: /** A helper object to manage the image properties. */ protected WritablePropertySourceImpl properties = null; Subclasses might have to override the PlanarImage implementation of WritablePropertySource methods to obtain desired property behavior. 2.9.1.4 Implement PropertyChangeEmitter Enable a java.beans.PropertyChangeListener to monitor image properties in the JAI sense of the term. If any PropertyChangeListeners are registered with the PlanarImage when one of its properties changes, a PropertyChangeEventJAI will be fired which will have as its source the PlanarImage object, a propertyName set to the name of the image property in question, and old and new values equal to the previous and current values of the image property. Either the old or the new values may be null. The PropertyChangeEmitter interface methods will likely be implemented using a protected variable which is an instance of the utility class java.beans.PropertyChangeSupport. 2.9.2 RenderedOp 2.9.2.1 Improve Property Encapsulation Internal modification: change RenderedOp to use the property accessors and mutators instead of dereferencing the inherited properties Hashtable. 2.9.2.2 Implement OperationNode The internal implementation will be revised to utilize an instance of the utility class OperationNodeSupport in conjunction with the inherited PropertyChangeSupport variable. 2.10 Renderable Class Modifications 2.10.1 RenderableOp 2.10.1.1 Change Class Definition Make RenderableOp implement ImageJAI instead of PropertySource: * Implement getClass(name). * Change setProperty() to return a boolean value. (This should have no effect on API users as it previously returned nothing, i.e., was void.) * Implement removeProperty(). 2.10.1.2 Implement PropertyChangeEmitter Make modifications like those made for PlanarImage. 2.10.1.3 Implement OperationNode Make modifications like those made for RenderedOp. Note that currently no RenderingHints are stored in a node. If a cache of hints were added to the node it could be used in the manner of the hints stored in each instance of the JAI class: hints stored in the node would be "merged" with any passed in when one of the createRendering() methods was invoked. Hints passed in to the method would, as with JAI.create(), take precedence. 2.10.2 MultiResolutionRenderableImage Implement ImageJAI. Will require implementing WritablePropertySource. 2.10.3 RenderableImageAdapter Implement ImageJAI instead of PropertySource. Will require implementing methods in WritablePropertySource and not in PropertySource. 2.11 Miscellaneous Class Modifications 2.11.1 Collection Class Modifications The JAI Collection architecture specifies very limited property management capabilities. This topic will be addressed in greater detail in a separate proposal dealing with the JAI CollectionImage architecture in general. The following changes should be made: * CollectionImage should implement WritablePropertySource methods not in PropertySource. * CollectionImage should implement PropertyChangeEmitter like PlanarImage. * CollectionOp should implement OperationNode like RenderedOp. 2.11.2 Other Modifications ImageMIPMap should implement ImageJAI. 3. Retention of Property Name Case Property names are currently case-insensitive in terms of property queries via the getProperty() method of the PropertyGenerator() and PropertySource() interfaces. All properties stored via setProperty() have their names forced to lower case. As a result invoking getPropertyNames() will return different names from those passed to setProperty() if any upper case characters were used. The property mechanism will be modified so that the storage of property names is case-retentive instead of case-insensitive. This means that when property values are stored or retrieved the case of the property names will be ignored insofar as the name is used as a key for the property value but that getPropertyNames() will return the property name strings as they were originally specified either by a call to setProperty() or by the PropertyGenerator (or by whatever originally set the name, e.g., on an externally generated RenderedImage). The required modifications will be to all implementations of PropertySource as well as to the OperationRegistry. 4. Property Synchronization In the current implementation of JAI if the value of a property at a given node depends on the value of one or more properties of the sources of the node then the value of the destination property may change if the value of any of the source properties on which it depends changes. For example, if the source node of a unary geometric operation has an ROI property set on it then the default behavior is to warp the ROI using the geometric mapping applied to transform the image. If the source ROI changes between distinct invocations of getProperty("ROI") on the destination node then different destination ROIs will be returned. This behavior is inconsistent with the synchronous behavior of image data computation. One method of synchronizing the property value would be to cache it locally once it is computed. When a property value is requested from a node of whatever type, the locally cached properties always take precedence over those which are calculated dynamically or inherited from source images. 4.1 RenderedOp 4.1.1 Locally Cache Dynamic Properties The property value on a RenderedOp would be synchronized by caching all dynamically generated properties via the superclass setProperty() method. This would involve a trivial modification of the source code of the getProperty() method. 4.1.2 Response to RenderingChangeEvents When a rendering needs to be cleared in response to a RenderingChangeEvent as described in "Support for Editing Rendered Op Chains", all properties which were not "manually" set on the node by user invocation of setProperty() should be cleared. To enable RenderedOp to respond to events in this fashion, setProperty() will be modified to store the names of all properties which were set by invoking setProperty() on the RenderedOp. Any locally cached properties the (lower case) names of which are not in this set will be cleared in response to a RenderingChangeEvent which completely clears the rendering of the node. 4.2 RenderableOp Property values would be cached as in RenderedOp. 4.3 CollectionOp Collection operator nodes currently do not support any type of dynamic property management. This capability will be added. As previously noted, this topic will be addressed in greater detail in a separate proposal. 4.4 Dynamic Properties To enable retrieval of properties the values of which change in response to changes in their property environment OperationNode defines the method getDynamicProperty(). This method will not return any property which is stored in the local cache of properties unless the property was set by an invocation of setProperty() on the node. Locally cached properties not stored due a setProperty() call would have been generated dynamically in a property environment which may be different from that at the time of invocation of this method. 5. Multiple Property Name Spaces No specific modifications will be made directly to handle multiple name spaces for image properties. This problem should however be able to be addressed indirectly using existing and proposed capabilities of JAI. 5.1 Hierarchical Name Space Convention Property name space collisions could be prevented if all property names were generated in adherence to an hierarchical naming convention. This could for example be based on the package name of the core package which generates the properties. The names generated by JAI itself will not adhere to the aforementioned naming convention, but this should not pose a problem if users adopt this convention for their own property names. 5.2 PropertySources as Properties Another method of handling multiple property name spaces would be to define a separate PropertySource for each name space of properties. These PropertySources could themselves be attached to images as properties. Inheritance of these properties would occur by the default mechanism. Modification of these properties within an operation chain could be managed by PropertyGenerators which are capable of recognizing these properties. The proposed convenience classes PropertySourceImpl and WritablePropertySourceImpl should aid in the implementation of objects to represent alternate name spaces. 6. Property Specification Clarification The documentation changes described in this section will be added in an attempt to clarify the specification. 6.1 PropertySource Replace related sections of class description with the following: *

The interface includes the getProperty() and * getPropertyNames() methods familiar from the * RenderedImage and RenderableImage interfaces. * Classes which implement this interface should do so in a manner which * treats the property names as case-retentive. That is to say that as * concerns operations effected using the property name as a key, the * operation should ignore the case of the property name while on the * other hand the property name retrieval methods should return the names * with their case preserved. * *

PropertySource is implemented by the ImageJAI * interface and, among other classes, by PlanarImage, * RenderableOp and CollectionImage. * Since all RenderedImages used with JAI are "wrapped" * by a RenderedImageAdapter, all JAI RenderedImages * may be assumed to implement PropertySource. Add comments related to multiple name spaces: *

Property name space collisions may be prevented by adhering to * an hierarchical naming convention. This could for example be based * on the name of the package in question, e.g., * com.sun.media.jai.MyProperty. * The names of properties generated by JAI itself will not adhere to the * aforementioned naming convention, but this should not pose a problem if * users adopt this convention for their own property names. *

Another approach to handling multiple property name spaces would * be to define a separate PropertySource for each name space of properties. * These PropertySources could themselves be attached to images as properties. * Inheritance of these properties would occur by the default mechanism. * Modification of these properties within an operation chain could be * managed by PropertyGenerators which are capable of recognizing these * properties. Note that a potential problem with this approach exists * when a PropertySourceChangeEvent is fired: it might be * necessary to clone the entire tree of properties in order to obtain * the old value of event object. 6.2 PropertyGenerator Comments for getPropertyNames(): * Returns an array of Strings naming properties emitted * by this property generator. The Strings may contain * characters of any case. Comments for getProperty(String,RenderedOp): * Computes the value of a property relative to an environment * of pre-existing properties emitted by the sources of * a RenderedOp, and the parameters of that operation. Comments for getProperty(String,RenderableOp): * Computes the value of a property relative to an environment * of pre-existing properties emitted by the sources of * a RenderableOp, and the parameters of that operation. * *

The operation name, sources, and ParameterBlock * of the RenderableOp being processed may be obtained by * means of the op.getOperationName, * op.getSources(), and op.getParameterBlock() * methods. It is legal to call getProperty() on the * operation's sources. 6.3 OperationRegistry This section has been superseded by the OperationRegistry proposal. 6.4 RenderedOp Class comments: *

The property environment of a RenderedOp is initially * derived from that of the corresponding OperationDescriptor * as maintained by the OperationRegistry. It may be modified * locally by adding PropertyGenerators, directives to copy * certain properties from specific sources, or requests to suppress certain * properties. These modifications per se cannot be undone directly but * may be eliminated as a side effect of other changes to the node as * described below. * *

The RenderedOp itself synthesizes several property values, * which may neither be set nor removed. These are: image_width, * image_height, image_min_x_coord, and * image_min_y_coord. These properties are referred to as * synthetic properties. * *

When a property value is requested an attempt will be made to derive * it from the several entities in the following order of precedence: *

    *
  1. synthetic properties;
  2. *
  3. local properties;
  4. *
  5. the rendering of the node;
  6. *
  7. any registered PropertyGenerators, or *
    a source specified via a copy-from-source directive;
  8. *
  9. the first node source which defines the property.
  10. *
* Local properties are those which have been cached locally either by virtue * of direct invocation of setProperty() or due to caching of a * property derived from the property environment. * *

All dynamically computed properties of a RenderedOp which * have been cached locally, i.e., those cached properties which were not set * by an explicit call to setProperty(), will be cleared when any * of the critical attributes of the node is edited. By implication these * properties will also be cleared when a RenderingChangeEvent * is received from any node source. 6.5 RenderableOp Class comments: *

The property environment of the RenderableOp is initially * derived from that of the corresponding OperationDescriptor * as maintained by the OperationRegistry. It may be modified * locally by adding a PropertyGenerator or by suppressing a * specific property. These modifications cannot be undone. * *

When a property value is requested an attempt will be made to derive * it from the several entities in the following order of precedence: *

    *
  1. local properties;
  2. *
  3. any registered PropertyGenerators, or *
    a source specified via a copy-from-source directive;
  4. *
  5. the first source which defines the property.
  6. *
* Local properties are those which have been cached locally either by virtue * of direct invocation of setProperty() or due to caching of a * property derived from the property environment. * *

The properties of a RenderableOp node are copied to each * rendering generated by any of the createRendering() methods. * Properties already set on the rendering are not copied, i.e., those of the * rendering take precedence. 6.6 CollectionOp The following comments would be equally a propos in the proposal "Image Collection API Modifications" but are included here in the context of the previous similar comment modifications. Class comments: *

The property environment of a CollectionOp is initially * derived from that of the corresponding OperationDescriptor * as maintained by the OperationRegistry. It may be modified * locally by adding PropertyGenerators, directives to copy * certain properties from specific sources, or requests to suppress certain * properties. These modifications per se cannot be undone directly but * may be eliminated as a side effect of other changes to the node as * described below. * *

When a property value is requested an attempt will be made to derive * it from the several entities in the following order of precedence: *

    *
  1. local properties;
  2. *
  3. any registered PropertyGenerators, or *
    a source specified via a copy-from-source directive;
  4. *
  5. the first source which defines the property.
  6. *
* Local properties are those which have been cached locally either by virtue * of direct invocation of setProperty() or due to caching of a * property derived from the property environment. * *

All dynamically computed properties of a CollectionOp which * have been cached locally, i.e., those cached properties which were not set * by an explicit call to setProperty(), will be cleared when any * of the critical attributes of the node is edited. By implication these * properties will also be cleared when a CollectionChangeEvent * is received from any node source.