Date post: | 20-Jan-2016 |
Category: |
Documents |
Upload: | scot-warner |
View: | 219 times |
Download: | 0 times |
1
1. Runtime Type Identification (RTTI)2. Reflection3. Components - Beans4. Events5. Properties
2
Object typesEach 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 !
3
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• Discovers dynamic type at runtime
public void dynamic(A a) {
a.f(); // always possible
if(a instanceof B) ((B)a).g();
if(a instanceof C) ((C)a).h();
}
NOT allowed :
String s=“B”;
… instanceof s
4
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());
}
}
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());
}
}
Static type : Object
Dynamic type : A, B or C
5
RTTI mechanicsThe 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 e.g. A.class
Static Class-method :Class.forName(“class_name”) e.g. Class.forName(“A”)
Object-method : <object_reference>.getClass() e.g. a.getClass()
Runtime type checking
static (named typed only) :
<object_reference> instanceof A
dynamic :
<class_reference>.isInstance(<object_reference>);
6
Example :Count A, B and C
class A {}
class B extends A{}
class C extends A{}
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]));
}
}
Number of objects of type class A : 10
Number of objects of type class B : 3
Number of objects of type class C : 4
7
Checking types
instanceofisInstance
true if type-relation between object and class exists
==equals
(on class objects) true if IDENTICAL Class-objects(no type-relation checking)
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();
instanceof A B C Ia true false false falseb true true false falsec true true true true
.getClass()== A.class B.class C.class I.classa true false false falseb false true false falsec false false true false
8
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()
9
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;}
// …}
10
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
11
Class introspection
public Members only (+superclasses)
use xxxDeclaredXxx to retrieve
all declared Members(no superclass info !)
12
Type infoimport 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 !");
}
printInfo(cA); printDeclaredInfo(cA);
}
}
Does not contain any info about type to print info on
13
Type infoAll 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()
public final native void java.lang.Object.notifyAll()
-----------------------------------------------------------------------------
All declared members of class A
public int A.a
private int A.b
private A(int,int)
public A()
public java.lang.String A.toString()
public void A.f()
public void A.fInit(int,int)
public void A.fInit()
----------------------------------------------------------------------------
class A{
public int a;
private int b;
public A() {System.out.println("A()"); }
private A(int aa,int bb) {a=aa;b=bb;}
public String toString() {return "A["+a+",+"+b+"]";}
public void f() {System.out.println("f()");}
public void fInit() {a=0;b=0;}
public void fInit(int aa,int bb) {a=aa;b=bb;}
}
java TypeInfo A
14
Making objectsclass 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);
} catch(Exception e) {System.err.println(e);}
}
}
class A{
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;}
public String toString() {return "A["+a+", "+b+"]";}
public void f() {System.out.println("f()");}
public void fInit() {a=0;b=0;}
public void fInit(int aa,int bb) {a=aa;b=bb;}
}
java MakeObject A
A()
A[0,0]
A(int,int)
A[5,10]
15
Manipulating Fieldsclass 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]
16
Invoking Methodsclass 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;
try{
o=cA.newInstance();
System.out.println(o);
} catch(Exception e) {System.err.println(e);}
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);
}
}
java Invoke A
A()
A[0,0]
public void A.fInit(int,int)
A[5,10]
17
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
18
Introduction
a (often used) definition
purpose • Build applications rapidlycheaplyreliably
reusing (standard) pieces of code• component = building block (cf. Lego-system)
“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)
19
Introduction
examples
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
• 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)
• MS-components (COM, DCOM, OLE, ActiveX)
20
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
• component selection• component configuration (properties)• specification of behavior
“Programmer”
Application Code
21
The beans model
In Java : component is ordinary class following conventions
Exported state : properties
Behavior
Property name : xxxWrite method : setXxx()Read method : getXxx()
alternative for booleans : isXxx()
“ordinary” methods public
event system (for component wiring)
Event name : XxxEvent (extends EventObject)Listener type : XxxListenerRegister listener : addXxxListener(XxxListener)Deregister listener : removeXxxListener(XxxListener)
22
Inspecting Beans
Application Builder Tool
Bean
intr
osp
ecti
on
BeanInfo
introspectio
n
EventSetDescriptor[] getEventSetDescriptors()
PropertyDescriptor[] getPropertyDescriptors()
MethodDescriptor[] getMethodDescriptors()
Image getIcon(int)
BeanInfo b=null;
try {
b=Introspector.getBeanInfo(aBean);
} catch(IntrospectionException e) {}
• for bean Xxx, XxxBeanInfo is searched• if not available : reflection is used to extract info
23
Making/using a BeanMaking a Bean
Bean Usage
• 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 codejavac a/A.java
• package the Beans in single jar-archivejar cfm a.jar manifest.tmp a/*.class
• 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
24
A simple Beanpackage 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;
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) {
super.paintComponent(g);
g.setColor(col); g.fillOval(0,0,rad,rad);
}
public void actionPerformed(ActionEvent e) {
col = (col==Color.RED) ? Color.GREEN : Color.RED;
repaint(0,0,rad,rad);
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,""));}
}
• properties : color, radius• public methods :
• setRadius / getRadius• setColor / getColor• paintComponent• actionPerformed• addActionListener/removeActionListener• notifyListeners
• event handling• sink for ActionEvent• source of ActionEvent
25
Retrieving Bean informationpublic 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());
}
}
}
26
Retrieving Bean informationjava 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)
Add listener method : public void circle.Circle.addActionListener(java.awt.event.ActionListener)
Remove listener method :public void circle.Circle.removeActionListener(java.awt.event.ActionListener)
27
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 c create new archive
t create table of contents
x extract from archive
f specify archive file name
m specify base manifest file
e.g. jar tf circle.jarjar cfm circle.jar manifest.tmp circle/*.class
Beans manifest file Manifest-Version: 1.0
Name: circle/Circle.class
Java-Bean: True
Empty line
Manifest file In directory containing circle
Invoke jar from this directory
28
Events and Listeners
Event Source object
Event Listenerobject
RegisterDeregister
Event notification
Event
29
Events and ListenersOwn event type and listener interface
public interface ColorListener extends java.util.EventListener {
public void colorChanged(ColorEvent e);
}
ColorListener.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;}
}
ColorEvent.java
30
Events and Listenerspublic 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));
}
}
Circle.java
java Info circle.Circle javax.swing.JPanel…
Events :
Event listener type interface circle.ColorListener
Listener method : public abstract void circle.ColorListener.colorChanged(circle.ColorEvent)
Add listener method : public void circle.Circle.addColorListener(circle.ColorListener)
Remove listener method :public void circle.Circle.removeColorListener(circle.ColorListener)
31
Unicast Eventsunicast 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;
}
}
32
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));
}
}
33
Multicast Eventsmulticast 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
34
Multicast Eventspublic 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);
}
}
}
35
Multicast Eventspublic 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);
}
}
}
36
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
37
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
38
Notifying ChangesBound Properties
Provide a mechanism to notify changes of property values
• Event type : PropertyChangeEvent• Listener interface : PropertyChangeListener• Listener method :
public void propertyChange(PropertyChangeEvent e)
39
Notifying ChangesBound Properties
Non-specific property binding
Specific property binding
public void addPropertyChangeListener (PropertyChangeListener l);
public void removePropertyChangeListener (PropertyChangeListener l);
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);}
// …
}
Fire ChangeEvents AFTER values are updated !
40
Support for Property Changes
• inherit from PropertyChangeSupport• use instance of PropertyChangeSupport
41
Vetoing ChangesConstrained Properties
Provide a mechanism to prevent changes in other Beans
Non-specific property binding
Specific property binding
public void addVetoalbeChangeListener (VetoableChangeListener l);
public void removeVetoableChangeListener (VetoableChangeListener l);
public void add<PropertyName>Listener (VetoableChangeListener l);
public void remove<PropertyName>Listener (VetoableChangeListener l);
Getting/setting
public void set<PropertyName> (<PropertyType> value)
throws PropertyVetoException;
public <PropertyType> get(<PropertyName>);
42
Reaching agreement
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
• Event type : PropertyChangeEvent• Listener interface : VetoableChangeListener• Listener method :
public void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException
43
Reaching agreementpublic 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);
}
}
44
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