Download JavaBeans2

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
1.
2.
3.
4.
5.
Runtime Type Identification (RTTI)
Reflection
Components - Beans
Events
Properties
1
Object types
Each Object reference has two types :
- static type
- known at compile time
- compiler enforces static code soundness checks
- does not change
- dynamic type (only known at run time – can change)
A a;
for(int i=0;i<5;i++) {
a=(i%2==0) ? new B() : new C();
a.f();
}
Enforced at
compile-time
Problem :
- specific operation desired depending on run time type
- standard solution : use polymorphism
- if not possible … -> RTTI needed !
2
Why RTTI ?
• Special, type dependent operations needed
• Only supertype available
public void dynamic(A a) {
a.f(); // always possible
// call g() if B-object
// call h() if C-object
}
Special operator :
instanceof <TYPE literal>
• Limitation : only NAMED types allowed (no expressions !)
• Implicitly used when downcasting
NOT allowed :
• Discovers dynamic type at runtime
String s=“B”;
public void dynamic(A a) {
… instanceof s
a.f(); // always possible
if(a instanceof B) ((B)a).g();
if(a instanceof C) ((C)a).h();
}
3
Example :
Count B
class A {}
class B extends A{}
class C extends A{}
class CountingB {
private ArrayList l=new ArrayList();
public void fillList(int n) {
for(int i=0;i<n;i++) {
int r=(int)(Math.random()*3);
if(r==0) l.add(new A());
else if(r==1) l.add(new B()); else l.add(new C());
}
Static type : Object
}
Dynamic type : A, B or C
public int countB() {
int r=0;
for(int i=0;i<l.size();i++) if((l.get(i)) instanceof B) r++;
return r;
}
public static void main(String[] args) {
CountingB b=new CountingB(); b.fillList(10);
System.out.println("Number of B-objects : "+b.countB());
}
}
4
RTTI mechanics
The class Class
• runtime info for each class/interface contained in special object (created by JVM)
• “special object” of type Class (meta-class)
• runtime-type in the Class-object
• Class-object stored in “.class”-file
• JVM loads object stored in class-file as needed (when first used)
How to get reference to Class-object ?
Class literal :
<class_name>.class
Static Class-method :Class.forName(“class_name”)
Object-method :
<object_reference>.getClass()
e.g.
e.g.
e.g.
A.class
Class.forName(“A”)
a.getClass()
Runtime type checking
static (named typed only) :
<object_reference> instanceof A
dynamic :
<class_reference>.isInstance(<object_reference>);
5
Example :
Count A, B and C
class A {}
Number of objects of type class A : 10
class B extends A{}
Number of objects of type class B : 3
class C extends A{}
Number of objects of type class C : 4
class Counting {
private ArrayList l=new ArrayList();
public void fillList(int n) {/* as before */ }
public int count(Class c) {
int r=0;
for(int i=0;i<l.size();i++) if(c.isInstance(l.get(i))) r++;
return r;
}
public static void main(String[] args) {
Class[] c={A.class,B.class,C.class};
Counting b=new Counting();
b.fillList(10);
for(int i=0;i<c.length;i++)
System.out.println("Number of objects of type "+c[i]+" : "+b.count(c[i]));
}
}
6
Checking types
instanceof
isInstance
true if type-relation between object
and class exists
==
(on class objects)
equals
interface I {}
class A{}
class B extends A{}
class C extends B implements I {}
//…
A a=new A();
B b=new B();
C c=new C();
true if IDENTICAL Class-objects
(no type-relation checking)
instanceof
a
b
c
A
true
true
true
B
false
true
true
C
false
false
true
I
false
false
true
.getClass()==
a
b
c
A.class
true
false
false
B.class
false
true
false
C.class
false
false
true
I.class
false
false
false
7
More Class methods
• public String getName()
• public Package getPackage()
• public boolean isInterface()
• public boolean isPrimitive()
• public boolean isArray()
• public Class getSuperClass()
• public Class[] getInterfaces()
• public boolean isAssignableFrom(Class c)
• public int getModifiers()
8
Using RTTI
• Mostly to cope with 3rd party code (components !)
• Design with much RTTI syntax probably flawed ! (redesign)
• Sometimes unavoidable
Idiom to check for object equality (for Collections-framework)
class A {
// …
public boolean equals(Object o) {
if(o instanceof A) {
// safe downcast to class A
// check for logical equality and return boolean
} else return false;
}
// …
}
9
RTTI vs Reflection
“classical” RTTI
reflection
• Type info known at compile and runtime
• discovers type from a known set of types
• does type-dependent actions (actions known at compile time)
• Type info only known at runtime
• discovers type + type info (e.g. constructors)
• does type-dependent actions (actions NOT necessarily known
at compile time)
• meta-level programming
Motivation for reflection
• write programs to handle unknown types
• JVM itself
• Rapid Application Development environments
• JUnit
• Java serialization mechanism
• RMI : discover capabilities of remote objects
10
Class introspection
public Members only (+superclasses)
use xxxDeclaredXxx to retrieve
all declared Members
(no superclass info !)
11
Type info
import java.lang.reflect.*;
class TypeInfo {
public static void printInfo(Class cl) {
System.out.println("All public members of "+cl);
Constructor[] c=cl.getConstructors();
Field[] f=cl.getFields();
Method[] m=cl.getMethods();
for(int i=0;i<f.length;i++) System.out.println(f[i]);
for(int i=0;i<c.length;i++) System.out.println(c[i]);
for(int i=0;i<m.length;i++) System.out.println(m[i]);
System.out.println("-----------------------------------------------------------------------------");
}
public static void printDeclaredInfo(Class cl) {
System.out.println("All declared members of "+cl);
// same as above, but with <Declared> in method calls
}
public static void main(String[] args) {
Class cA=null;
try { cA=Class.forName(args[0]);
} catch(ClassNotFoundException e) {
System.err.println("Class not found !");
}
Does not contain any info
printInfo(cA); printDeclaredInfo(cA);
about type to print info on 12
}
}
Type info
All public members of class A
public int A.a
public A()
public java.lang.String A.toString()
public void A.f()
public void A.fInit(int,int)
public void A.fInit()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public final native void java.lang.Object.notify()
java TypeInfo A
public final native void java.lang.Object.notifyAll()
----------------------------------------------------------------------------class A{
All declared members of class A
public int a;
public int A.a
private int b;
private int A.b
public A() {System.out.println("A()"); }
private A(int,int)
private A(int aa,int bb) {a=aa;b=bb;}
public A()
public String toString() {return "A["+a+",+"+b+"]";}
public java.lang.String A.toString()
public void f() {System.out.println("f()");}
public void A.f()
public void fInit() {a=0;b=0;}
public void A.fInit(int,int)
public void fInit(int aa,int bb) {a=aa;b=bb;}
public void A.fInit()
}
13
Making objects
class MakeObject {
public static void main(String[] args) {
Class cA=null;
Object[] par={new Integer(5),new Integer(10)};
Class[] param={int.class,int.class};
try {cA=Class.forName(args[0]);
} catch(ClassNotFoundException e) {
System.err.println("Class not found !");
}
Object o1=null,o2=null;
try{
o1=cA.newInstance(); System.out.println(o1);
Constructor c=cA.getDeclaredConstructor(param);
o2=c.newInstance(par); System.out.println(o2);
class A{
} catch(Exception e) {System.err.println(e);}
public int a;
}
private int b;
}
public A() {System.out.println("A()"); }
public A(int aa,int bb) {System.out.println("A(int,int)");a=aa;b=bb;}
java MakeObject A
public String toString() {return "A["+a+", "+b+"]";}
A()
public void f() {System.out.println("f()");}
A[0,0]
public void fInit() {a=0;b=0;}
A(int,int)
14
public void fInit(int aa,int bb) {a=aa;b=bb;}
A[5,10]
}
Manipulating Fields
class ManiField {
public static void main(String[] args) {
Class cA=null;
Object[] par={new Integer(5),new Integer(10)};
Class[] param={int.class,int.class};
try {cA=Class.forName(args[0]);
} catch(ClassNotFoundException e) {
System.err.println("Class not found !");
}
Object o=null;
try{
o=cA.newInstance();
System.out.println(o);
} catch(Exception e) {System.err.println(e);}
Field[] f=cA.getDeclaredFields();
try {
for(int i=0;i<f.length;i++)
if(f[i].getType()==int.class) f[i].setInt(o,100);
} catch(IllegalAccessException e) {
System.err.println(e);
}
System.out.println(o);
}
}
java ManiField A
A()
A[0,0]
java.lang.IllegalAccessException: Class ManiField can not
access a member of class A with modifiers "private"
A[100,0]
15
Invoking Methods
class ManiField {
public static void main(String[] args) {
Class cA=null;
try {cA=Class.forName(args[0]);
} catch(ClassNotFoundException e) {
System.err.println("Class not found !");
}
Object o=null;
java Invoke A
try{
A()
o=cA.newInstance();
A[0,0]
System.out.println(o);
public void A.fInit(int,int)
} catch(Exception e) {System.err.println(e);}
A[5,10]
Method m=null;
try{m=cA.getDeclaredMethod("fInit",param);
} catch(NoSuchMethodException e) {System.err.println(e);}
System.out.println(m);
try{m.invoke(o,par);
} catch(IllegalAccessException e) {System.err.println(e);
} catch(InvocationTargetException e) {System.err.println(e);}
System.out.println(o);
}
}
16
A meta-program
Write a method that for a given Class :
-constructs an object using the no-arg constructor
-invokes arbitrary order all methods on this object
- containing “f” in their name
- having an empty parameter list
17
Introduction
purpose
• Build applications
rapidly
cheaply
reliably
reusing (standard) pieces of code
• component = building block (cf. Lego-system)
a (often used) definition
“A software component is a unit of composition with contractually specified
interfaces and explicit context dependencies only. A software component
can be deployed independently and is subject to composition by third parties.”
(Szyperski and Pfister, 1997)
18
Introduction
characteristics
• application consists of composition of components
• component is larger than single class (“unit of deployment)
• component conforms to specifications
- interfaces offered
- naming conventions
• often : only compiled/binary version available for building applications
• delivered by 3rd parties
examples
• shared libraries
• Windows DynicamicLinkLibrary (*.DLL)
• Unix Dynamic Libraries (*.so)
• OO component technologies
• Corba Component Model (CCM)
• Java components
• visual programming : JavaBeans
• server side component framework : EnterpriseJavaBeans (EJB)
19
• MS-components (COM, DCOM, OLE, ActiveX)
Visual Programming
• visual programming : draw program (cf. electronic circuit design)
- pieces of codes needed from tool palette
- configure code
- wire pieces (interactions)
• earlier technologies : Visual Basic, Delphi, LabView
• visual programming key to “Rapid Application Development” (RAD)
Application Builder Tool
Component
Repository
Application
Code
“Programmer”
• component selection
• component configuration (properties)
• specification of behavior
20
The beans model
In Java : component is ordinary class following conventions
Exported state : properties
Behavior
Property name : xxx
Write method : setXxx()
Read method : getXxx()
alternative for booleans : isXxx()
“ordinary” methods
public
event system (for component wiring)
Event name : XxxEvent (extends EventObject)
Listener type : XxxListener
Register listener : addXxxListener(XxxListener)
Deregister listener : removeXxxListener(XxxListener)
21
Inspecting Beans
BeanInfo b=null;
try {
b=Introspector.getBeanInfo(aBean);
} catch(IntrospectionException e) {}
introspection
Application Builder Tool
BeanInfo
Bean
EventSetDescriptor[] getEventSetDescriptors()
PropertyDescriptor[] getPropertyDescriptors()
MethodDescriptor[] getMethodDescriptors()
Image getIcon(int)
• for bean Xxx, XxxBeanInfo is searched
• if not available : reflection is used to extract info
22
Making/using a Bean
Making a Bean
• create Bean source code (A.java file) in dedicated package (a)
(possibly > 1 bean per package)
• provide Bean public properties (according to pattern)
• provide Bean public methods
• provide Bean event code (source/sink of events)
• compile the Beans code
javac a/A.java
• package the Beans in single jar-archive
jar cfm a.jar manifest.tmp a/*.class
Bean Usage
• import the Bean in a standard IDE (e.g. NetBeans) or
dedicated RAD-environment (e.g. Sun’s Bean Development Kit – BDK)
• drop Beans on application form
• configure Bean properties
• connect Beans through events
• generate code/compile/run application
23
A simple Bean
package circle;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class Circle extends JPanel implements Serializable, ActionListener {
private ActionListener l;
private int rad=0; private Color col=Color.RED;
• properties : color, radius
public void setRadius(int newRad) {rad=newRad;}
• public methods :
public int getRadius() {return rad;}
• setRadius / getRadius
public void setColor(Color c) {col=c;}
• setColor / getColor
public Color getColor() {return col;}
• paintComponent
public void paintComponent(Graphics g) {
• actionPerformed
super.paintComponent(g);
• addActionListener/removeActionListener
g.setColor(col); g.fillOval(0,0,rad,rad);
}
• notifyListeners
public void actionPerformed(ActionEvent e) {
• event handling
col = (col==Color.RED) ? Color.GREEN : Color.RED;
• sink for ActionEvent
repaint(0,0,rad,rad);
• source of ActionEvent
notifyListeners();
}
public void addActionListener(ActionListener ll) {l=ll;}
public void removeActionListener(ActionListener ll) {if(l==ll) l=null;}
public void notifyListeners() {if(l!=null) l.actionPerformed(new ActionEvent(this,0,""));}
24
}
Retrieving Bean
information
public class Info {
public static void main(String[] args) {
BeanInfo b=null;
Class info=null,stop=null;
try {info=Class.forName(args[0]);stop=Class.forName(args[1]);} catch(Exception e) { }
try { b=Introspector.getBeanInfo(info,stop);
} catch(IntrospectionException e) {}
PropertyDescriptor[] p=b.getPropertyDescriptors();
MethodDescriptor[] m=b.getMethodDescriptors();
EventSetDescriptor[] e=b.getEventSetDescriptors();
System.out.println("Properties :"); for(int i=0;i<p.length;i++) {
System.out.println("Property name : "+p[i].getName());
System.out.println("\tType : "+p[i].getPropertyType());
System.out.println("\tReadMethod : "+p[i].getReadMethod());
System.out.println("\tWriteMethod : "+p[i].getWriteMethod());
}
System.out.println("Methods :"); for(int i=0;i<m.length;i++) { System.out.println("Method : "+m[i].getMethod()); }
System.out.println("Events :"); for(int i=0;i<e.length;i++) {
System.out.println("Event listener type "+e[i].getListenerType());
Method[] lm=e[i].getListenerMethods();
for(int j=0;j<lm.length;j++) System.out.println("\tListener method : "+lm[j]);
System.out.println("\tAdd listener method : "+e[i].getAddListenerMethod());
System.out.println("\tRemove listener method :"+e[i].getRemoveListenerMethod());
}
25
}
}
Retrieving Bean
information
java Info circle.Circle javax.swing.JPanel
Properties :
Property name : color
Type : class java.awt.Color
ReadMethod : public java.awt.Color circle.Circle.getColor()
WriteMethod : public void circle.Circle.setColor(java.awt.Color)
Property name : radius
Type : int
ReadMethod : public int circle.Circle.getRadius()
WriteMethod : public void circle.Circle.setRadius(int)
Methods :
Method : public void circle.Circle.actionPerformed(java.awt.event.ActionEvent)
Method : public void circle.Circle.addActionListener(java.awt.event.ActionListener)
Method : public java.awt.Color circle.Circle.getColor()
Method : public int circle.Circle.getRadius()
Method : public void circle.Circle.notifyListeners()
Method : public void circle.Circle.paintComponent(java.awt.Graphics)
Method : public void circle.Circle.removeActionListener(java.awt.event.ActionListener)
Method : public void circle.Circle.setColor(java.awt.Color)
Method : public void circle.Circle.setRadius(int)
Events :
Event listener type interface java.awt.event.ActionListener
Listener method : public abstract void java.awt.event.ActionListener.actionPerformed(java.awt.event.ActionEvent)
26
Add listener method : public void circle.Circle.addActionListener(java.awt.event.ActionListener)
Jarring the Beans
jar utility
• group java files in one archive
• originally meant to reduce complexity of Applet download
• contains meta-information (manifest file)
• MUST be added to CLASSPATH variable !
mostly used options
e.g.
c
t
x
f
m
create new archive
create table of contents
extract from archive
specify archive file name
specify base manifest file
jar tf circle.jar
jar cfm circle.jar manifest.tmp circle/*.class
Beans manifest file
Manifest-Version: 1.0
Empty line
Name: circle/Circle.class
Java-Bean: True
Manifest file In directory containing circle
Invoke jar from this directory
27
Events and Listeners
Register
Deregister
Event Source
object
Event
notification
Event Listener
object
Event
28
Events and Listeners
Own event type and listener interface
ColorListener.java
public interface ColorListener extends java.util.EventListener {
public void colorChanged(ColorEvent e);
}
ColorEvent.java
public class ColorEvent extends java.util.EventObject {
private Color c;
public ColorEvent(Object o,Color cc) {super(o);c=cc;}
public Color getColor() {return c;}
}
29
Events and Listeners
Circle.java
public class Circle extends JPanel implements Serializable, ActionListener {
private ColorListener l;
private int rad=0;
private Color col=Color.RED;
public void setRadius(int newRad) {rad=newRad;}
public int getRadius() {return rad;}
public void setColor(Color c) {col=c;}
public Color getColor() {return col;}
public void paintComponent(Graphics g) {/* as before */}
public void actionPerformed(ActionEvent e) {/* as before */}
public void addColorListener(ColorListener ll) {l=ll;}
public void removeColorListener(ColorListener ll) {if(l==ll) l=null;}
public void notifyListeners() {
if(l!=null) l.colorChanged(new ColorEvent(this,col));
}
}
java Info circle.Circle javax.swing.JPanel
…
Events :
Event listener type interface circle.ColorListener
Listener method : public abstract void circle.ColorListener.colorChanged(circle.ColorEvent)
30
Add listener method : public void circle.Circle.addColorListener(circle.ColorListener)
Remove listener method :public void circle.Circle.removeColorListener(circle.ColorListener)
Unicast Events
unicast events : one listener only !
throw TooManyListenersException if attempt to register > 1 listener !
public void add<ListenerType> (<ListenerType> l) throws java.util.TooManyListenersException;
public void remove<ListenerType>(<ListenerType> l);
public class TheBean {
MyEventListener l=null;
// …
public void addMyEventListener(MyEventListener ll) throws java.util.TooManyListenersException {
if(l==null) l=ll;
else throw new java.util.TooManyListenersException();
}
public void removeMyEventListener(MyEventListener ll) {
if(l==ll) l=null;
}
}
31
Unicast Events
public class Circle extends JPanel implements Serializable, ActionListener {
private ColorListener l;
private int rad=0;
private Color col=Color.RED;
public void setRadius(int newRad) {rad=newRad;}
public int getRadius() {return rad;}
public void setColor(Color c) {col=c;}
public Color getColor() {return col;}
public void paintComponent(Graphics g) {/* as before */}
public void actionPerformed(ActionEvent e) {/* as before */}
public void addColorListener(ColorListener ll) throws java.util.TooManyListenersException {
if(l==null) l=ll;
else throw new java.util.TooManyListenersException();
}
public void removeColorListener(ColorListener ll) {if(l==ll) l=null;}
public void notifyListeners() {
if(l!=null) l.colorChanged(new ColorEvent(this,col));
}
}
32
Multicast Events
multicast events : possibly many listeners !
public void add<ListenerType> (<ListenerType> l);
public void remove<ListenerType>(<ListenerType> l);
Issues with multithreading
• listeners get notified on caller’s thread
• event handler possibly/often done in separate thread
• problems :
• call back to event source object from different thread
• list of listeners can get modified during event notification
Programming guidelines
• DO NOT invoke listener method from synchronized block (deadlock danger !)
• make copy of list of listeners BEFORE notification
• by default, make all public bean methods SYNCHRONIZED
33
Multicast Events
public class TheBean {
private ArrayList listeners = new ArrayList();
// …
public synchronized void f() {
// …
}
public void addMyEventListener(MyEventListener ll) {
if(!(listeners.contains(ll)) listeners.add(ll);
}
public void removeMyEventListener(MyEventListener ll) {
if(listeners.contains(ll)) listeners.remove(ll);
}
public void notifyListeners() {
MyEvent evt=new MyEvent(this);
ArrayList l;
synchronized(this) {
l=(ArrayList) listeners.clone();
}
for(int i=0,s=l.size();i<s;i++) {
MyEventListener c=(MyEventListener)(l.get(i));
c.listenToMyEvent(evt);
}
}
}
34
Multicast Events
public class Circle extends JPanel implements Serializable, ActionListener {
private ArrayList listeners=new ArrayList();
private int rad=0;
private Color col=Color.RED;
public synchronized void setRadius(int newRad) {rad=newRad;}
public synchronized int getRadius() {return rad;}
public synchronized void setColor(Color c) {col=c;}
public synchronized Color getColor() {return col;}
public synchronized void paintComponent(Graphics g) {/* as before */}
public synchronized void actionPerformed(ActionEvent e) {/* as before */}
public void addColorListener(ColorListener ll) { if(!(listeners.contains(ll))) listeners.add(ll);}
public void removeColorListener(ColorListener ll) { if(listeners.contains(ll)) listeners.remove(ll);}
public void notifyListeners() {
ColorEvent evt=new ColorEvent(this,col);
ArrayList l;
synchronized(this) {
l=(ArrayList) listeners.clone();
}
for(int i=0,s=l.size();i<s;i++) {
ColorListener c=(ColorListener)(l.get(i));
c.colorChanged(evt);
}
}
35
}
Properties and
Indexed Properties
public void set<PropertyName> (<PropertyType> value);
public <PropertyType> get<PropertyName>();
public boolean is<PropertyName>();
public class TheBean {
private MyType obj;
private int anInt;
private boolean bool;
public synchronized void setObject(MyType m) {obj=m;}
public synchronized MyType getObject() {return obj;}
public synchronized void setInt(int a) {anInt=a;}
public synchronized int getInt() {return anInt;}
public synchronized void setB(boolean b) {bool=b;}
public synchronized boolean isB() {return bool;}
// …
PropertyName :
}
• object
• int
•b
36
Properties and
Indexed Properties
public void set<PropertyName> (<PropertyType>[ ] value);
public <PropertyType>[ ] get<PropertyName>();
public void set<PropertyName> (int index, <PropertyType> value);
public <PropertyType> get<PropertyName>(int index);
public class TheBean {
private int[] a;
private ArrayList l;
public synchronized void setA(int index,int val) {a[index]=val;}
public synchronized int getA(int index) {return a[index];}
public synchronized void setMyString(int index,String v) {l.set(index,o);}
public synchronized String getMyString(int index) {return (String)(l.get(index));}
// …
}
PropertyName :
•a
• myString
37
Notifying Changes
Bound Properties
Provide a mechanism to notify changes of property values
• Event type : PropertyChangeEvent
• Listener interface : PropertyChangeListener
• Listener method :
public void propertyChange(PropertyChangeEvent
e)
38
Notifying Changes
Bound Properties
Non-specific property binding
public void addPropertyChangeListener (PropertyChangeListener l);
public void removePropertyChangeListener (PropertyChangeListener l);
Specific property binding
Fire ChangeEvents AFTER values are updated !
public void add<PropertyName>Listener (PropertyChangeListener l);
public void remove<PropertyName>Listener (PropertyChangeListener l);
public class TheBean {
private ArrayList changeA=new ArrayList();
private ArrayList change=new ArrayList();
public int a=0,b=0;
public void addPropertyChangeListener (PropertyChangeListener l) {change.add(l);}
public void addAListener(PropertyChangeListener l) {changeA.add(l);}
// …
39
}
Support for
Property Changes
• inherit from PropertyChangeSupport
• use instance of PropertyChangeSupport
40
Vetoing Changes
Constrained Properties
Provide a mechanism to prevent changes in other Beans
Getting/setting
public void set<PropertyName> (<PropertyType> value)
throws PropertyVetoException;
public <PropertyType> get(<PropertyName>);
Non-specific property binding
public void addVetoalbeChangeListener (VetoableChangeListener l);
public void removeVetoableChangeListener (VetoableChangeListener l);
Specific property binding
public void add<PropertyName>Listener (VetoableChangeListener l);
public void remove<PropertyName>Listener (VetoableChangeListener l);
41
Reaching agreement
• Event type : PropertyChangeEvent
• Listener interface : VetoableChangeListener
• Listener method :
public void vetoableChange(PropertyChangeEvent e)
throws PropertyVetoException
setProperty(newValue)
• bean does own validity checking : if not valid throw PropertyVetoException
• notify all VetoableChangeListeners of attempt to change to new value
• if PropertyVetoException is thrown :
• notify all registered VetoableChangeListeners with old value
• event source is allowed to IGNORE second round PropertyVetoExceptions
• if no PropertyVetoException is thrown :
• update the value
• notify all registered PropertyChangeListeners with new value
42
Reaching agreement
public class TheBean {
private int a=0;
private ArrayList change=new ArrayList(),veto=new ArrayList();
public void addPropertyChangeListener(PropertyChangeListener l) {change.add(l);}
public void addVetoableChangeListener(VetoableChangeListener l) {veto.add(l);}
public void setA(int n) throws PropertyVetoException {
if(!(isValidValue(n)) throw new PropertyVetoException(this);
try {
fireVetoableChangeListeners(n);
} catch(PropertyVetoException e) {
try {
fireVetoableChangeListeners(a);
} catch(PropertyVetoException ee) {} // ignore
throw e;
// rethrow
}
a=n;
// update
firePropertyChangeListeners(n);
}
}
43
Support for
Vetoable Changes
• inherit from VetoableChangeSupport
• use instance of VetoableChangeSupport
• fireVetoableChange
• throws PropertyVetoException
• notifies in 2 rounds :
• 1st round : new value
• if exceptions : 2nd round : old value
• rethrows exception if raised
44
Related documents