Getting Listener from JavaBeans
TM
An amendment to the javabeans specification
Hans Muller and Mark Davidson
Presently all of the state in an AWT component that can be written can also be read, eg there are no write-only properties in the component API. Event listeners are a notable exception. AWT event listeners are managed according to the JavaBeans conventions with a PAIR of Methods: addfoolistener () And removefoolistener () for a listener That Implements the foolistener interface.
No access is provided to the listener lists themselves. The fields that contain the listener lists may be private, package private or protected and no methods are provided to return the contents of the listener lists. This has caused some problems for Swing and other AWT clients :
The Swing UI classes have to keep references to every listener they add, just to enable removing them if the UI is changed. Swing applications contain 1000's of references like this. In general, you can not clear any JavaBeans listener list unless you've kept a private copy. Archiving systems have to resort to implementation dependent snooping to discover the contents of listener lists. Externalization is not an option for classes derived from Component, like the Swing components, because the listeners are inaccessible.
To mitigate the problem in Java 2 Standard Edition (J2SE) v 1.3 we added a getListeners (Class) method to Component and to the Swing classes that defined listener lists. The getListeners (Class) method uses a Class as its argument to specify a particular . listener list For example to get all of the listeners added with addFocusListener (), one would write: exposing listener lists was getListeners (FocusListener.class) .This particular approach to taken to minimize the overall change to the AWT / Swing public API. IT WAS NOT INDTENTED TO BE A PATTERN for All JavaBeans and It Did Not Handle PropertyChangelisteners - Which Can Be Added To A Single Property, AS IN AddPropertyChangeListener ("MyProperty", MyListener.
.............
Solution
The Javabeans Specification Has Been Extended So That Listener Lists CAN Optionally Be Read. Two Extensions Have Been Added:
To the add / remove pattern for listeners: add an optional get
.................. ..
The additional methods and classes presented in this amendment have been implemented for Java 2 Standard Edition (J2SE) v 1.4. JavaBeans which have been written that extend Beans in the java.awt or javax.swing packages will automatically pick up the implementation of this amendment For EXISTING LISTENERS WHEN J2SE 1.4 is used. if The Extended Bean Defines Additional Listeners
All additions or changes to the javabeans specification is in red
6.5 Event Listener Registration
...
Public void add Public Void Remove Public ... The add The get 6.5.1 Event Registration EXAMPLE Public Abstract Class Model { ... Private list listener = new arraylist (0); Public synchronized void modelchangedlistener [] getModelchangedlisteners () { Return (MODELCHANGEDLISTENER []) (Listeners.Toarray ()); } ... } 7.4.1 Bound Properties ... The PropertyChangeListener event listener interface is used to report updates to simple bound properties If a bean supports bound properties then it should support the set of multi-cast event listener registration methods for PropertyChangeListeners:. Public void addPropertyChangeListener (PropertyChangeListener x); Public Void RemovePropertyChangeListener (PropertyChangelistener); Public propertychangelistener [] getPropertyChangelisteners (); ... The getPropertyChangeListeners method is optional. It was added in the XX revision of this specification and as a consequence beans defined per earlier revisions do not support it. Also, the getPropertyChangeListeners method may return a mixture of PropertyChangeListeners and PropertyChangeListenerProxy objects (which implement PropertyChangeListener) If The Bean Supports Listening on Named Properties. See Section 7.4.5.1 (Section Number May Change - MSD) for Details. 7.4.2 Constrained Properties ... ... if a bean supports constrained Properties Then It Should Support a Normal Set of Multi-Cast Event Listener Registration Methods for VetoableChangeListeners: Void AddVetoableChangelistener (VetoableChangeListener X); Void RemoveveToableChangelistener (VetoableChangeListener X); VETOABLECHANGELISTENER [] GETVETOABLECHANGELISTENERS (); The getVetoableChangeListeners method is optional. It was added in the XX revision of this specification and as a consequence beans defined per earlier revisions do not support it. Also, the getVetoableChangeListeners method may return a mixture of VetoableChangeListeners and VetoableChangeListenerProxy objects (which implement VetoableChangeListener) if the bean supports listening on named properties See Section 7.4.5.1 (section number may change - msd). for details.7.4.5 Optional support for listening on named propertiesIn addition to supporting the standard design pattern for adding, retrieving and removing PropertyChangeListeners shown in Section 7.4.1 above, a bean that fires PropertyChangeEvents may also support an additional set methods that allow a PropertyChangeListener to be Added, Retrieved and Removed for a named property: Void AddPropertyChangelistener (String PropertyName) PropertyChangelistener Listener; Void RemovePropertyChangeListener (String PropertyName) PropertyChangelistener Listener; PropertyChangelistener [] getPropertyChangelisteners (String PropertyName); In this Case, The Bean Should Associate The Given Listener with The Given Property Name, And Only Invoke It's PropertyChange Method When the Given Named Property Has Been Changed. Similarly, in addition to supporting the standard additional registration methods for adding and removing VetoableChangeListeners, beans may also support addition registration methods that are tied to a specific named property: Void AddveToableChangelistener (String PropertyName, VETOABLECHANGELISTENER LISTENER); Void RemoveveToableChangeListener (String PropertyName, VETOABLECHANGELISTENER LISTENER); VETOABLECHANGELISTENER [] GETVETOABLECHANGELISTENERS (String PropertyName); 7.4.5.1 Retrieval of Listener for Named Properties When listeners for named properties are added to a bean, the zero argument retrieval method getPropertyChangeListeners (or similarly, getVetoableChangeListeners) will return all the listeners added to the bean. For beans which support named properties, the definition of getListeners () has been extended to mean that it would return the real listener, or a subclass of an EventListenerProxy for listeners added with additional parameters. Subclasses of EventListenerProxys may be used to identify the listeners associated with specific named properties. If the calling method is interested in distinguishing the listeners from the getXXXListeners () method, then it must check each element to see if its an EventListenerProxy or subclass, perform the appropriate cast and extract the additional parameters. For example, if a PropertyChangeListener was added with a named property to a bean with the addPropertyChangeListener ( "propertyName", listener), then the no argument getPropertyChangeListeners () method may return a set of PropertyChangeListeners and PropertyChangeListenerProxys. If the calling method is interested in Retrieving the name of the property, The IT Must Test Each Element To See if ITS a PropertyChangeListenerProxy. . Import java.awt. *; Import java.beans. *; Public Class JellyBean { ... Public propertychangelistener [] getPropertyChangelisteners () { Return Changes.getPropertyChangeListeners (); ... Public vetoablechangelistener [] getvetoablechangelisteners () { Return Vetos.getVetoableChangeListeners (); } ... } Javadoc for EventListenerProxy Package java.util; / ** * An Abstract Wrapper Class for An EventListener Class Which Associates A Set of * Additional parameters with the listener. Subclasses Must Provide The Storage and * Accessor Methods for the additional arguments or parameters. * * Subclasses of EventListenerProxy May Be Returned by getListeners () Methods * as a way of associating named property with their listener. * * * @since 1.4 * / Public class eventlistenerProxy import1Listener { PRIVATE FINAL EVENTLISTENER LISTENER; / ** * @Param Listener the listener Object * @Param Parameters List of parameters associated with the listener. * / Public EventListenerProxy (EventListener Listener) / ** * @Return the listener associated with this proxy. * / Public eventlistener getListener () } / ** * A class which extends the EventListenerProxy Specification * for adding a named PropertyChangeListener. Instances of. INSTANCES OF * This class can be added as propertychangelistener to * an Object. * * If The Object Has A getPropertyChangeListeners () * Method THE ARRAY RETURNED COULD BE A MIXTURE OF * PropertyChangelistener and propertyChangeListenerProxy * Objects. * * For Example, a bean Which supports named Properties Would Have A Two Argument * Method Signature for Adding a propertychangelistener for a property: * * Public Void AddPropertyChangeListener (String PropertyName) * PropertyChangelistener Listener; * * If the bean also importenend: * * Public propertyChangeListener [] getPropertyChangeListeners (); * * THEN THE ARRAY May Contain PropertyChangeListeners Which Are Also * PropertyChangeListenerProxy Objects. * * If the calling method is interested in retrieving the named protety kiln ing * Would Have to Test The Element to See if ITS a Proxy Class. * * @see java.util.eventListenerProxy * @since 1.4 * / Public Class PropertyChangeListenerProxy Extends EventListenerProxy Implements propertychangelistener { / ** * Constructor Which Binds The PropertyChangeListener to a Specific Property. * * @Param Listener the listener Object * @Param PropertyName The name of the property to listen on. // xxx - MSD NOTE: i change the order of the arguments so that it's similar to // PropertyChangeSupport.addpropertychangelistener (string, propertychangelistener) * / Public PropertyChangelistenerProxy (String PropertyName, PropertyChangelistener Listener / ** * @Param Listener the listener Object * @Param Parameters List of parameters associated with the listener. * / Public PropertyChangelistenerProxy (PropertyChangelistener Listener, Object [] Parameters) / ** * Forwards the property change.. * * @Param Evt The Property Change Event * / Public Void PropertyChange (PropertyChangeEvent EVT) / ** * Returns the name of the named protety associated with the * Listener. * / Public string getpropertyName () } / ** * A class which extends the EventListenerProxy Specification * for adding a named VetoableChangeListener. Instances of * this class can be added as vetoablechangelistener to * an Object. * * If The Object Has A GetVetoableChangelisteners () * Method Then The Array Returned Could Be a MixTure of * VETOABLECHANGELISTENER AND VETOABLECHANGELISTENERPROXY * Objects. * * @see #EventListenerProxy * @since 1.4 * / Public Class VetoableChangeListenerProxy Extends EventListenerProxy Implements vetoablechangelistener { / ** * @Param PropertyName The name of the property to listen on. * @Param Listener the listener Object // xxx - MSD NOTE: i change the order of the arguments so that it's similar to // PropertyChangeSupport.addpropertychangelistener (string, propertychangelistener) * / Public VetoableChangelistenerProxy (String PropertyName, VETOABLECHANGELISTENER LISTENER) / ** * @Param Listener the listener Object * @Param Parameters List of parameters associated with the listener. * / Public VetoableChangeListenerProxy (VetoableChangelistener Listener, Object [] Parameters) / ** * Forwards the property change.. * / Public Void VetoableChange (PropertyChangeEvent EVT) / ** * Returns the name of the named protety associated with the * Listener. * / Public string getpropertyName () } 8.4 Design Patterns for Events ... WE LOOK for a set of methods of the form: Public Void Add Public Void Remove Public Where the first two methods Take the Same " ... The get Public void addfredListener (FredListener T); Public void RemovefredListener (FredListener T); Public FredListener [] getfredListeners (); Defines a Multi-cast evenet Source 8.4.1 Unicast Event Sources Implement The Same Changes as The Multi-Cast Example Javadoc for EventSetDescriptor (Additional Contructors and Accessor Method) / ** * This Constructor create from scratch using * String names. * * @Param SourceClass The class firing the event. * @Param EventsetName The Programmatic Name of The Event Set. * Note That this will Normal Start with a Lower-Case Character. * @Param Listenertype The Class of The Target Interface That Events * Will Get Delivered TO. * @Param ListenerMethodNames the names of the methodnods That Will Get Called * WHEN The Event Gets Delivered to Its Target Listener Interface. * @Param addlistenerMethodName the name of the method on the event source * That can be used to register an estener object. * @Param RemovelistenerMethodName the name of the method on the evening SOURCE * That Can be used to de-register an estener object. * @Param getListenerMethodName the name of the method on the evenet source * That can be used to access the array of event listener objects. * @Exception IntrospectionException if An Exception Occurs Database * Introspection. * @since 1.4 * / Public EventSetDescriptor (Class SourceClass, String EventsetName, Class Listenertype, String ListenerMethodNames [], String AddListenerMethodName, String RemovelistenerMethodName, String getListenerMethodName) THROWS IntrospectionException / ** * This Constructor create from scratch using * java.lang.reflect.method and java.lang.class objects. * * @Param EventsetName The Programmatic Name of The Event Set. * @Param Listenertype The Class for the Listener Interface. * @Param ListenerMethods An Array of Method Objects Describing EACH * of The Event Handling Methods in The Target Listener. * @Param AddListenerMethod The Method on The Event Source * That can be used to register an estener object. * @Param RemovelistenerMethod The Method on The Event Source * That Can be used to de-register an estener object. * @Param getListenerMethod the Method on the Event Source * That Can be used to access the array of event listener object. * @Exception IntrospectionException if An Exception Occurs Database * Introspection. * @since 1.4 * / Public EventsetDescriptor (String EventsetName, Class Listenertype, Method ListenerMethods [], Method AddListenerMethod, Method RemovelistenerMethod, Method getListenerMethod) THROWS IntrospectionException / ** * Gets The Method Used to Access The Event Listeners. * * @Return The Method Used to Access The Array of listeners At the * Event Source or Null if it doesn't exist * @since 1.4 * / Public Method getGetListenerMethod () Implementation detailsthe get Changes to java.beans.eventsetdscriptor ..................... .. For Backwards Compatibility, The EventSetDescriptor Will NOT FAIL INTLISTENER () Methods Do Not ExistNer () Will Return Null SystemMethod () Will Return Null IF That Method Doesn't exist. Changes to java.beans.propertychangesupport PropertyChangeSupport Has Had The Following Methods Added: Public propertychangelistener [] getPropertyChangelisteners (); Public propertyChangelistener [] getPropertyChangelisteners (String propertyName); Changes to java.beans.vetoableChangeSupport VETOABECHANGESUPPORT HAS HAD The FOLLOWING METHODS Added: Public vetoablechangelistener [] getvetoablechangelisteners (); Public VetoableChangelistener [] getvetoablechangelisteners (String propertyName);