620 likes | 860 Views
JavaBeans Event Handling and Properties. Handling Bean Events Event Objects, Listeners, and Sources Event Adapters Property Management Indexed, Bound and Constrained Properties Introspection - Design Patterns Explicitly Defining Bean Information. Event Handling and Properties.
E N D
Handling Bean Events Event Objects, Listeners, and Sources Event Adapters Property Management Indexed, Bound and Constrained Properties Introspection - Design Patterns Explicitly Defining Bean Information Event Handling and Properties
Java Event Model • Events Are Objects In Java • JavaBeans Model based on Event Handling introduced in Java 1.1 API • Event Objects Are Generated By Components for Communication between Beans • Events Propagate from Source to Target Listener Objects • java.util package provides base classes
Base class: java.util.EventObject public EventObject(Object source) Encapsulates information about event References Source of Event Create Event-Specific Subclasses of EventObject Event Objects
EventObject Example • public class VoltsChangedEvent extends java.util.EventObject • { • protected double theVolts; • public VoltsChangedEvent(Object source, double volts) • { • super(source); • theVolts = volts; • } • public double getVolts() • { • return theVolts; • } • }
KeyEvent MouseEvent ContainerEvent ComponentEvent ActionEvent ItemEvent WindowEvent AdjustmentEvent AWTEvent Classes
java.beans package Sent when bound or constrained properties are altered JavaBeans must generate and send PropertyChangeEvent objects PropertyChangeEvent
Listeners receive events from source objects Methods are invoked on the listener and event object is passed as a parameter To receive event notification, a class implements a listener interface Listener Interface Base class: java.util.EventListener An event fired by a source object will cause the associated method of the listener object to be called Listener Objects
EventListener Example • public interface VoltsChangeListener • extends java.util.EventListener • { • void voltsChanged(VoltsChangedEvent e); • }
ActionListener public void actionPerformed(ActionEvent e); ItemListener public void itemStateChanged(ItemEvent e); MouseListener public void mouseClicked(MouseEvent e); public void mouseEntered(MouseEvent e); public void mouseExited(MouseEvent e); public void mousePressed(MouseEvent e); public void mouseReleased(MouseEvent e); Some AWT Listener Interfaces & Methods
java.beans.PropertyChangeListener Bound Properties public void propertyChange(PropertyChangeEvent e); java.beans.VetoableChangeListener Constrained Properties public void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException; Java Beans Listeners
Objects that fire events Register and Unregister Listeners Registration Design Patterns public void addEventNameListener (EventNameListener l); public void removeEventNameListener (EventNameListener l); public EventNameListener[] getEventNameListeners (); Event Sources
Multicast - Multiple Listeners Registered with Single Event Source Unicast - Only one Listener Registered with Single Event Source Unicast Registration Design Patterns public void addEventNameListener (EventNameListener l) throws java.util.TooManyListenersException; public void removeEventNameListener (EventNameListener l); public EventNameListener getEventNameListener (); Unicast and Multicast Event Delivery
Event Source Example • import java.util.Vector; • public class Battery • { • protected double currentVolts = 12.0; • private Vector voltsChangeListeners = new Vector(); • public Battery(double initVoltage) • { currentvolts = initVoltage; } • public Battery() {}
Event Source Example - Continued • public synchronized void • addVoltsChangeListener(VoltsChangeListener l) • { • if (!voltsChangeListeners.contains(l)) • voltsChangeListeners.addElement(l); • } • public synchronized void • removeVoltsChangeListener(VoltsChangeListener l) • { • if (voltsChangeListeners.contains(l)) • voltsChangeListeners.removeElement(l); • }
Event Source Example - Continued • public synchronized VoltsChangeListener[] • getVoltsChangeListeners() • { • return (VoltsChangeListener []) • voltsChangeListeners.toArray( • new VoltsChangeListener[ • voltsChangeListeners.size()]); • }
Event Source Example - Continued • protected void notifyVoltsChange() • { • VoltsChangedEvent e = • new VoltsChangedEvent(this, currentVolts); • Vector v; • synchronized(this) { • v = (Vector) voltsChangeListeners.clone();} • int cnt = v.size(); • for(int i = 0; i < cnt; i++) • { • VoltsChangeListener list = • (VoltsChangeListener)v.elementAt(i); • list.voltsChanged(e); • } • } • } // delimits Class definition
Use the add<event>Listener() method to register a qualified listener with a specific source object Appropriate add<event>Listener() methods are available to source components which trigger the specific events This example shows that the argument of the method is the listener object button.addActionListener(this); Registering an AWT Listener Object
The Recharger Class • public class Recharger implements VoltsChangeListener • { • protected Battery theBattery; • public Recharger(Battery b) • { • theBattery = b; • theBattery.addVoltsChangeListener(this); • } • public void voltsChanged(VoltsChangedEvent e) • { • // turn the charging switch on or off • } • }
Listener code could get unmanageable Listener may want to receive several different event source objects Listener may want to listen to several objects generating the same event Event Adapters
Handling Events with Adapters Event Source Register Listener Fire Event Event Adapter Event Object Create Adapter Forward Event Event Listener Event Object
Single Instance Generic Adapter Event Listener Handler1() Handler2() Handler3() Forward Events Adapter Fire Events Event Source 1 Event Source 2 Event Source 3
Target makes an instance of the Adapter Adapter discovers the target class at runtime Adapter discovers the target methods at runtime Adapter can invoke the target method Implementing a Dispatch Table using Java Reflection
Finding the Class • Battery b = new Battery(12.5); • Recharger rech = new Recharger(b); • try { • Class theClass = rech.getClass(); • } • catch(java.lang.ClassNotFoundException e) {} • ALSO: • Class theClass = Recharger.class;
Assume a setName method for the Recharger class with the following signature: Finding the Method • void setName(String s); • Battery b = new Battery(12.5); • Recharger rech = new Recharger(b); • try { • Class theClass = rech.getClass(); • Class paramClasses[] = { java.lang.String.class }; • java.lang.reflect.Method m = • theClass.getMethod(“setName”,paramClasses); • Object param[] = { new String(“Recharger One”) }; • m.invoke(rech, param); • } • catch(Exception e) {}
Handles multiple Battery objects as event sources Maps to arbitrary target object, an instance of Recharger Dispatch methods all have the same signature: public void <methodName> (VoltsChangedEvent e); Generic Voltage Adapter
Voltage Adapter Example • import java.lang.reflect.*; • import java.util.*; • public class GenericVoltageAdapter • implements VoltsChangeListener • { • protected Object theTarget; • protected Class theTargetClass; • protected final static Class paramClass[] = • { VoltsChangedEvent.class }; • protected Hashtable map = new Hashtable(); • public GenericVoltageAdapter(Object target) • { • theTarget = target; • theTargetClass = target.getClass(); }
Voltage Adapter Example - Continued • public void registerEventHandler • (Battery bat, String methodName) throws NoSuchMethodException • { • Method m = theTargetClass.getMethod(methodName, paramClass); • bat.addVoltsChangeListener(this); • map.put(bat, m); • } • public void voltsChanged(VoltsChangedEvent e) { • try { • Method m = (Method)map.get(e.getSource()); • Object params[] = { e }; • m.invoke(theTarget, params); • } • catch (Exception e) {System.out.println(e);} }
Revised Recharger Class • public class Recharger • { • protected Battery battOne; • protected Battery battTwo; • protected GenericVoltageAdapter voltAdapter; • public Recharger(Battery b1, Battery b2) • { • battOne = b1; battTwo = b2; • voltAdapter = new GenericVoltageAdapter(this); • voltAdapter.registerEventHandler(battOne, “volts1”); • voltAdapter.registerEventHandler(battTwo, “volts2”); • } • // do something specific to battery1 changes • public void volts1(VoltsChangedEvent e) { } • // do something specific to battery2 changes • public void volts2(VoltsChangedEvent e) { } • }
Data Portion of Bean Define Behavior and State Exposed to Visual Programming Tools for Customization Can Be Any Data Type NOT a one-to-one correspondence between Properties and data members of a class Properties in JavaBeans
Getter and Setter Methods Only Getter -> Read-only property Only Setter -> Write-only property Design Patterns: public void set<PropertyName> (<PropertyType> x); public <PropertyType> get<PropertyName>(); Boolean Property Design Pattern for Getter: public boolean is<PropertyName>(); Accessor Methods
Accessor Methods Example • import java.util.Vector; • public class Battery • { • protected double currentVolts = 12.0; • private Vector voltsChangeListeners = new Vector(); • // Constructors Here • public double getCurrentVoltage() { • return currentVolts; } • public void setCurrentVoltage(double v) { • currentVolts = v; • // other processing • }
Ordered collection of values associated with one name Implemented as an array Design Patterns for accessing all elements: public void set<PropertyName> (<PropertyType>[] x); public <PropertyType>[] get<PropertyName>(); Design Patterns for accessing single element: public void set<PropertyName> (int index, <PropertyType> x); public <PropertyType> get<PropertyName>(int index); Indexed Properties
Indexed Properties Example • public class Recharger • { • protected Battery[] battArray; • public void setBatteries(Battery[] b) { • battArray = b; } • public Battery[] getBatteries() { • return battArray; } • public void setBatteries(int index, Battery b) { • battArray[index] = b; } • public Battery getBatteries(int index) { • return battArray[index]; } • }
Support change notifications Non-specific property binding PropertyChangeEvent PropertyChangeListener Design Patterns for registering and unregistering listeners for Bound Properties public void addPropertyChangeListener(PropertyChangeListener l); public void removePropertyChangeListener(PropertyChangeListener l); Bound Properties
Constructor PropertyChangeEvent(Object source, String propName, Object oldValue, Object newValue); Methods public Object getNewValue(); public Object getOldValue(); public Object getPropagationId(); public String getPropertyName(); public void setPropagationId(Object propID); PropertyChangeEvent
PropertyChangeListener • public interface PropertyChangeListener • extends EventListener { • public void propertyChange(PropertyChangeEvent e); • }
Bound Property Example • import java.util.Vector; • import java.beans.*; • public class Battery • { • protected double currentVolts = 12.0; • protected Vector propChangeListeners = new Vector(); • public Battery(double initVoltage) • { currentvolts = initVoltage; } • public Battery() {}
Bound Property Example - Continued • public synchronized void • addPropertyChangeListener(PropertyChangeListener l) • { • if (!propChangeListeners.contains(l)) • propChangeListeners.addElement(l); • } • public synchronized void • removePropertyChangeListener(PropertyChangeListener l) • { • if (propChangeListeners.contains(l)) • propChangeListeners.removeElement(l); • }
Bound Property Example - Continued • protected void notifyVoltsChange() • { • PropertyChangedEvent e = • new PropertyChangedEvent(this, “CurrentVoltage”, • null, new Double(currentVolts)); • Vector v; • synchronized(this) { • v = (Vector) propChangeListeners.clone();} • int cnt = v.size(); • for(int i = 0; i < cnt; i++) • { • PropertyChangeListener list = • (PropertyChangeListener)v.elementAt(i); • list.propertyChange(e); • }} • } // delimits Class definition
Revised Recharger Class • public class Recharger implements PropertyChangeListener • { • protected Battery theBattery; • public Recharger(Battery b) • { • theBattery = b; • theBattery.addPropertyChangeListener(this); • } • public void propertyChange(PropertyChangeEvent e) • { • if(e.getSource() == theBattery && • e.getPropertyName() == “CurrentVoltage”) • { Battery b = (Battery)e.getSource(); • Object o = e.getNewValue(); • double newVoltage; • if ( o == null ) newVoltage = b.getCurrentVoltage(); • else newVoltage = ((Double)o).doubleValue(); } • }}
PropertyChangeSupport • import java.util.Vector; • import java.beans.*; • public class Battery extends PropertyChangeSupport • { • protected double currentVolts = 12.0; • public Battery(double initVoltage){ • this(); • currentvolts = initVoltage; } • public Battery() { super(this);} • public double getCurrentVoltage() { • return currentVolts; } • protected void notifyVoltsChange() { • firePropertyChange(“CurrentVoltage”, null, • new Double(currentVolts)); } • }
Constrained Properties • Enable Outside Party Validation • VetoableChangeListener • Design Patterns for registering and unregistering listeners for Constrained Properties public void addVetoableChangeListener(VetoableChangeListener l); public void removeVetoableChangeListener(VetoableChangeListener l); • PropertyVetoException • Design Patterns for setting and getting Constrained Properties public <PropertyType> get<PropertyName>(); public void set<PropertyName>(<PropertyType> v) throws PropertyVetoException
Using Bound & Constrained Properties • When Change is Vetoed, New Event must be fired • Listeners cannot assume universal acceptance of constrained property • Properties can be both Bound and Constrained • Fire VetoableChangeEvent • Change Property Value if no veto • Fire PropertyChangeEvent
Manages Constrained Properties Manages Firing of Events VetoableChangeSupport
Constrained Property Example • public class Recharger implements PropertyChangeListener • { • protected Battery theBattery; • protected double minVoltage = 12.0; • protected VetoableChangeSupport; • public Recharger(Battery b) • { • theBattery = b; • theBattery.addPropertyChangeListener(this); • vSupport = new VetoableChangeSupport(this); • } • public void addVetoableChangeListener(VetoableChangeListener l) • {vSupport.addVetoableChangeListener(l);} • public void removeVetoableChangeListener(VetoableChangeListener l) • {vSupport.removeVetoableChangeListener(l);}
Constrained Property Example - Continued • public double getMinimumVoltage() • { • return minVoltage; • } • public void setMinimumVoltage(double v) throws PropertyVetoException • { • if (v < 6.0) throw new PropertyVetoException(); • vSupport.fireVetoableChange(“MinimumVoltage”, • new Double(minVoltage), new Double(v)); • minVoltage = v; • } • } // delimits class definition
Design Patterns for registering and unregistering listeners for specific Bound Properties public void add<PropertyName>Listener(PropertyChangeListener l); public void remove<PropertyName>Listener(PropertyChangeListener l); Design Patterns for registering and unregistering listeners for specific Constrained Properties public void add<PropertyName>Listener(VetoableChangeListener l); public void remove<PropertyName>Listener(VetoableChangeListener l); Listeners for Specific Properties
Beans expose information about how they work Application builder tools analyze these features Low-Level Services: Reflection Facilities High-Level Services: Limited to Public Properties, Methods, and Events Design Patterns Introspection
Property Design Patterns Simple public <PropertyType> get<PropertyName>(); public void set<PropertyName>(<PropertyType> x); Boolean public boolean is<PropertyName>(); Indexed public <PropertyElement> get<PropertyName>(int i); public void set<PropertyName>(int i, <PropertyElement> x); public <PropertyElement> [] get<PropertyName>(); public void set<PropertyName>(<PropertyElement>[] x); Design Patterns Review