JavaBeans - Event Handling and Properties

advertisement
JavaBeans Event Handling
and Properties
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
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
Event Objects
 Base class: java.util.EventObject
 public EventObject(Object source)
 Encapsulates information about event
 References Source of Event
 Create Event-Specific Subclasses of
EventObject
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;
}
}
AWTEvent Classes
 KeyEvent
 MouseEvent
 ContainerEvent
 ComponentEvent
 ActionEvent
 ItemEvent
 WindowEvent
 AdjustmentEvent
PropertyChangeEvent
 java.beans package
 Sent when bound or constrained properties are
altered
 JavaBeans must generate and send
PropertyChangeEvent objects
Listener Objects
 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
EventListener Example
public interface VoltsChangeListener
extends java.util.EventListener
{
void voltsChanged(VoltsChangedEvent e);
}
Some AWT Listener
Interfaces & Methods
 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);
Java Beans Listeners
 java.beans.PropertyChangeListener
 Bound Properties
 public void propertyChange(PropertyChangeEvent e);
 java.beans.VetoableChangeListener
 Constrained Properties
 public void vetoableChange(PropertyChangeEvent e) throws
PropertyVetoException;
Event Sources
 Objects that fire events
 Register and Unregister Listeners
 Registration Design Patterns
public void addEventNameListener (EventNameListener l);
public void removeEventNameListener (EventNameListener l);
public EventNameListener[] getEventNameListeners ();
Unicast and Multicast Event
Delivery
 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 ();
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
Registering an AWT
Listener Object
 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);
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
}
}
Event Adapters
 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
Handling Events with
Adapters
Event Source
Register
Listener
Fire Event
Event
Object
Event Adapter
Forward
Event
Event
Object
Create
Adapter
Event Listener
Single Instance Generic
Adapter
Handler1()
Event Listener
Handler2()
Handler3()
Forward
Events
Adapter
Fire
Events
Event Source
1
Event Source
2
Event Source
3
Implementing a Dispatch
Table using Java Reflection
 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
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;
Finding the Method
 Assume a setName method for the Recharger
class with the following signature:
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) {}
Generic Voltage Adapter
 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);
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) { }
}
Properties in JavaBeans
 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
Accessor Methods
 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 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
}
Indexed Properties
 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 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]; }
}
Bound Properties
 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);
PropertyChangeEvent
 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);
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
VetoableChangeSupport
 Manages Constrained Properties
 Manages Firing of Events
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
Listeners for Specific
Properties
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);
Introspection
 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
Design Patterns Review
 Property Design Patterns
 Simple
public <PropertyType> get<PropertyName>();
public void set<PropertyName>(<PropertyType> x);
 Boolean
public boolean is<PropertyName>();
 Indexed
public
public
public
public
<PropertyElement> get<PropertyName>(int i);
void set<PropertyName>(int i, <PropertyElement> x);
<PropertyElement> [] get<PropertyName>();
void set<PropertyName>(<PropertyElement>[] x);
Design Patterns Review Continued
Event Design Patterns
 Multicast
public void add<EventListenerType>(<EventListenerType> x);
public void remove<EventListenerType>(<EventListenerType> x);
public <EventListenerType>[] get<EventListenerType>s();
 Unicast
public void add<EventListenerType>(<EventListenerType> x)
throws TooManyListeners;
 Method Design Patterns
 None specified
Explicitly Providing Bean
Information
 Alternative to Automatic Introspection
 Option for controlling Bean Information
 Can be used in combination with Automatic
Introspection
 BeanInfo interface
The Introspector
 java.beans.Introspector class
 Obtains Bean Information
 Two-tier approach
 Looks for explicit information
 Uses Reflection Techniques combined with
Design Patterns
The BeanInfo Interface
 Implemented by Bean Information Class
 Methods gather information about Bean
 Design Pattern:
 JavaBean class name: Car
 Associated BeanInfo class name: CarBeanInfo
 Advantage: Bean does not carry extra baggage
 Disadvantage: Tight Coupling Relying on
Design Pattern
BeanInfo Interface Methods
public BeanInfo[] getAdditionalBeanInfo(): returns additional
BeanInfo objects relevant to the main Bean
public BeanDescriptor getBeanDescriptor(): returns Bean Descriptor
public int getDefaultEventIndex(): returns default event index
public int getDefaultPropertyIndex(): returns default property index
public EventSetDescriptor[] getEventSetDescriptors(): returns event set
descriptors
public Image getIcon(int iconkind): returns specified icon
public MethodDescriptor[] getMethodDescriptors(): returns method
descriptors
public PropertyDescriptor[] getPropertyDescriptors(): returns property
descriptors
SimpleBeanInfo class
 Implements BeanInfo interface
 Derive your own BeanInfo class by
extending SimpleBeanInfo
 Additional convenience method:
public Image loadImage(String resourceName);
Bean Descriptor
 Describes class that implements the
Bean
 Constructor:
public BeanDescriptor(Class beanClass);
 Some FeatureDescriptor methods:
public void setDisplayName(String dispName);
public String getDisplayName();
Bean Descriptor Example
import java.beans.*;
public class RechargerBeanInfo extends SimpleBeanInfo
{
public BeanDescriptor getBeanDescriptor()
{
BeanDescriptor bd = new BeanDescriptor(Recharger.class);
bd.setDisplayName(“Simulated Recharger”);
return bd;
}
}
Setting Bean Icons
 Icons used in Palettes or Tool Bars
 Four supported .GIF formats
Icon
16 x 16 color
32 x 32 color
16 x 16 monochrome
32 x 32 monochrome
Constant
ICON_COLOR_16x16
ICON_COLOR_32x32
ICON_MONO_16x16
ICON_MONO_32x32
import java.beans.*;
import java.awt.Image;
Setting Bean Icons Example
public class RechargerBeanInfo extends SimpleBeanInfo
{
public Image getIcon(int iconKind)
{
if(iconKind == BeanInfo.ICON_COLOR_16x16) {
Image img = loadImage(“recharger.gif”);
return img; }
return null;
}
}
Summary
 Handling Bean Events
 Event Objects, Listeners, and Sources
 Event Adapters
 Property Management
 Indexed, Bound and Constrained Properties
 Introspection - Design Patterns
 Explicitly Defining Bean Information
Download