The material in this lesson is extremely important. However, there is simply too much material to be covered in detail during lecture periods. Therefore, students in Prof. Baldwin's Advanced Java Programming classes at ACC will be responsible for studying this material on their own, and bringing any questions regarding the material to class for discussion.
This lesson was originally written on October 19, 1997 using the software and documentation in the JDK 1.1.3 download package along with the April 97 release of the BDK 1.0 download package.
An object with constrained properties allows other objects to veto a constrained property value change. Constrained property listeners can veto a change by throwing a PropertyVetoException. |
This bean class is examined with the Introspector and is tested with a test program designed specifically to exercise the ability of the bean to broadcast an event to a list of registered VetoableChangeListener objects whenever the value of one of the properties becomes subject to change.
The bean will also be bound. As such, the test program will also confirm that the bean properly broadcasts an event to a list of registered PropertyChangeListener objects whenever the value of one of the properties actually changes.
Name of bean: Beans06 Class of bean: class Beans06 ==== Properties: ==== Name: preferredSize Type: class java.awt.Dimension Get method: public synchronized java.awt.Dimension Beans06.getPreferredSize() Set method: null Name: theColor Type: class java.awt.Color Get method: public synchronized java.awt.Color Beans06.getTheColor() Set method: public synchronized void Beans06.setTheColor(java.awt.Color) ==== Events: ==== Event Name: vetoableChange Add Method: public synchronized void Beans06.addVetoableChangeListener( java.beans.VetoableChangeListener) Remove Method: public synchronized void Beans06.removeVetoableChangeListener( java.beans.VetoableChangeListener) Event Type: vetoableChange Event Name: propertyChange Add Method: public synchronized void Beans06.addPropertyChangeListener( java.beans.PropertyChangeListener) Remove Method: public synchronized void Beans06.removePropertyChangeListener( java.beans.PropertyChangeListener) Event Type: propertyChange ==== Methods: ==== makeRed removePropertyChangeListener getTheColor setTheColor removeVetoableChangeListener getPreferredSize addPropertyChangeListener makeBlue addVetoableChangeListener |
The bean class developed for this lesson has the following property
which is both Bound and Constrained properties:
Name: theColor Type: class java.awt.Color Get method: public synchronized java.awt.Color Beans06.getTheColor() Set method: public synchronized void Beans06.setTheColor(java.awt.Color) |
The bean maintains a list of objects that request to be notified whenever there is a change in the value of the Bound propertie. It also maintains a list of objects that request to be notified whenever a property value is subject to change. This is often referred to as registering listener objects to receive an event.
Objects that request to be added to the first list mentioned above must be of a class that implements the PropertyChangeListener interface and defines the propertyChange() method that is declared in that interface.
Objects that request to be added to the second list must be of a class tha timplements the VetoableChangeListener interface and defines the vetoableChange() method that is declared in that interface.
Whenever the value of the property becomes subject to change, a vetoableChange() event is broadcast to all of the registered VetoableChangeListener objects. Those objects can either accept the change or veto it. An object that vetos the change does so by raising an exception.
The event is broadcast by invoking the vetoableChange() method on all of the objects on the list. When this method is invoked on a listener object, an object of type PropertyChangeEvent is passed as a parameter.
Note that the PropertyChangeEvent object passed as a parameter to the vetoableChange() method in the listener objects is the same type of object passed to the propertyChange() method for Bound properties. The object contains the following information:
As you can see, three of the parameters passed to the propertyChange() method are of type Object, and one is of type String. The parameters of type Object sometimes need to be downcast to the correct type to be used in the receiving method.
Notification of the VetoableChangeListener objects takes place before the change in the property value has occurred.
The following methods are available to extract information from the object passed as a parameter. These methods are defined by the PropertyChangeEvent class or its superclass, EventObject:
This program illustrates the use of beans with a property which is both bound and constrained.
The bean has one property named theColor. Two separate instance variables named oldColor and newColor are used to maintain the value of the property.
Applying introspection to the bean yields the results shown earlier in this lesson.
The most significant new addition to this bean class is the ability for a listener to veto a proposed change in the value of a property. When that happens, the proposed new property value is discarded and the actual property value is not changed.
The following methods:
Each of these methods receives a proposed new color value as a parameter when it is invoked. The method saves the current value of the property in the instance variable named oldColor. Then it makes a call to the method named notifyVetoableChange() inside a try block.
The notifyVetoableChange() method broadcasts a vetoableChange() event to all of the VetoableChangeListener objects that are registered to receive such an event. The broadcast is accomplished making use of the VetoableChangeSupport class which not only handles the firing of the event, but does some additional necessary processing as well.
Any listener object that wants to veto the change throws a PropertyVetoException which finds its way back to method listed above that invoked notifyVetoableChange() in the first place.
When the exception is thrown, it is caught in a catch block. The code in the catch block restores the property value to its original value and displays the exception. In other words, the proposed new value is replaced by the value of the property that existed before the proposed new value was received.
Whether it is vetoed or not, the proposed new value (or the replacement for the proposed new value) becomes the current value and is used to set the background color of the bean.
The proposed new value is also compared with the value of the property that existed before the proposed new value was received. If they are different (meaning that an actual property change has occurred) the notifyPropertyChange() method is invoked to broadcast a propertyChange() event to all PropertyChangeListener objects registered to receive such an event. If the property value didn't actually change, the propertyChange() event is not broadcast.
An important aspect of the behavior of this bean is based on the use
of the fireVetoableChange() method of the VetoableChangeSupport
class to actually broadcast the event. A description of this method
follows. Pay particular attention to the behavior of the method in the
circumstance where someone wants to veto the change.
public void fireVetoableChange(String propertyName, Object oldValue, Object newValue) throws PropertyVetoException Report a vetoable property update to any registered listeners. If anyone vetos the change, then fire a new event reverting everyone to the old value and then rethrow the PropertyVetoException. No event is fired if old and new are equal and non-null Parameters: propertyName - The name of the property that was changed. oldValue - The old value of the property. newValue - The new value of the property. Throws: PropertyVetoException if the recipient wishes the property change to be rolled back. |
protected Color oldColor; protected Color newColor; |
PropertyChangeSupport changeSupportObj; VetoableChangeSupport vetoSupportObj; |
newColor = Color.yellow; setBackground(newColor); |
The following code fragment in the constructor performs the required
instantiation. The constructor for these support classes requires an object
reference as a parameter. That object reference is later used to identify
the source of events fired by the support objects. In this case, we pass
the this reference in as a parameter to specify the bean as
the source of the events.
changeSupportObj = new PropertyChangeSupport(this); vetoSupportObj = new VetoableChangeSupport(this); |
When a listener object vetos a change, the event-firing mechanism in the support class automatically fires a second event specifying the old value as the new value. This has the effect of notifying all of the listener objects that the property value has been rolled back to its previous value. However, you must provide the code in the bean to actually implement the rollback.
The following method is invoked by all three of the methods listed above to implement the rollback. A veto occurs when one of the listener objects raises a PropertyVetoException. At the point where the following method is invoked, the current value of the property has been stored in the instance variable named oldColor and the proposed new value has been stored in the instance variable named newColor.
The code in the following method monitors for a veto by enclosing the call to the notifyVetoableChange() method inside a try block. If a listener object vetos the change, a PropertyVeotException will be raised and the code in the catch block will be executed. Otherwise, the code in the catch block will be skipped.
In the case of a veto, the current value is recovered from oldColor and stored in newColor, thereby replacing the proposed new value with the unchanged current value. From that point forward, the current value is used in place of the proposed new value because the proposed new value has been replaced by the current value..
Recall that the property is also bound to support a list of PropertyChangeListener objects who have registered to be notified whenever the property value actually changes. These listener objects should not be notified of a proposed change that isn't implemented because of a veto, because in that case no change actually took place.
An if statement is used to determine if the property value has actually changed, and if so, the PropertyChangeListener objects are notified. In the case of an actual change in the property value, the background color of the bean is also changed to reflect the new value. If there was no actual change, the background color is not changed.
This strategy is implemented by the code in the following method.
void processTheColors(){ try{//test to see if anyone vetos the new color notifyVetoableChange("theColor"); }catch(PropertyVetoException exception){ //Someone vetoed the new color. Don't use newColor. newColor = oldColor;// Restore oldColor instead //Display the veto exception System.out.println(exception); }//end catch if(!newColor.equals(oldColor)){//if color changed this.setBackground(newColor);//display new color //notify property listeners of property change notifyPropertyChange("theColor"); }//end if }//end process the colors |
public synchronized void setTheColor(Color inColor){ oldColor = newColor;//save current color newColor = inColor;//proposed new color processTheColors();//go process the proposed new color }//end setTheColor() public synchronized Color getTheColor(){ return oldColor; }//end getTheColor |
public synchronized void makeBlue(){ oldColor = newColor;//save current color newColor = Color.blue;//establish proposed new color processTheColors();//go process the proposed new color }//end makeBlue() //----------------------------------------------------// public synchronized void makeRed(){ oldColor = newColor;//save current color newColor = Color.red;//establish proposed new color processTheColors();//go process the proposed new color }//end makeRed() |
Note that unlike a sample program in a previous lesson where we "rolled
our own" list-maintenance capability, these methods simply make use of
the corresponding list-maintenance methods in the previously instantiated
object of type PropertyChangeSupport that is referenced by the reference
variable named changeSupportObj. This results in a significant reduction
in programming effort on our part.
//Add a property change listener object to the list. public synchronized void addPropertyChangeListener( PropertyChangeListener listener){ //Pass the task on to the support class method. changeSupportObj.addPropertyChangeListener(listener); }//end addPropertyChangeListener //-----------------------------------------------------// //Remove a property change listener from the list. public synchronized void removePropertyChangeListener( PropertyChangeListener listener){ //Pass the task on to the support class method. changeSupportObj.removePropertyChangeListener(listener); }//end removePropertyChangeListener() |
Similar to the previous discussion, these methods make use of the corresponding
list-maintenance methods in the previously instantiated object of type
VetoableChangeSupport that is referenced by the reference variable
named vetoSupportObj. Not having to create our own list-maintenance
code results in a significant reduction in programming effort on our part.
//Add a vetoable change listener object to the list. public synchronized void addVetoableChangeListener( VetoableChangeListener listener){ //Pass the task on to the support class method. vetoSupportObj.addVetoableChangeListener(listener); }//end addVetoableChangeListener //-----------------------------------------------------// //Remove a vetoable change listener from the list. public synchronized void removeVetoableChangeListener( VetoableChangeListener listener){ //Pass the task on to the support class method. vetoSupportObj.removeVetoableChangeListener(listener); }//end removeVetoableChangeListener() |
Note that this method makes use of the firePropertyChange() method
of an object of the PropertyChangeSupport class to actually fire
the event. This eliminates the requirement for us to write our own code
to fire the events to all the objects on the list of registered objects.
protected void notifyPropertyChange( String changedProperty){ //Pass the task on to the support class method. changeSupportObj.firePropertyChange( changedProperty,oldColor,newColor); }//end notifyPropertyChange() |
This method uses the fireVetoableChange() method of the VetoableChangeSupport
class to actually fire the event. As discussed earlier, the fireVetoableChange()
method actually performs some data processing and does more than simply
fire the event. In particular, if the proposed change is vetoed by a listener
object, another round of events is fired to "roll back" the value to the
value of the property before the proposed change.
protected void notifyVetoableChange( String vetoableProperty) throws PropertyVetoException{ //Pass the task on to the support class method. vetoSupportObj.fireVetoableChange( vetoableProperty,oldColor,newColor); }//end notifyVetoableChange() |
/*File Beans06.java Copyright 1997, R.G.Baldwin This program was designed to be compiled and executed under JDK 1.1.3 or later. This program illustrates the use of beans with a property which is both bound and constrained. The bean has one property named theColor. Two separate instance variables named oldColor and newColor are used to maintain the value of the property. Applying introspection to the bean yields the following: Name of bean: Beans06 Class of bean: class Beans06 ==== Properties: ==== Name: preferredSize Type: class java.awt.Dimension Get method: public synchronized java.awt.Dimension Beans06.getPreferredSize() Set method: null Name: theColor Type: class java.awt.Color Get method: public synchronized java.awt.Color Beans06.getTheColor() Set method: public synchronized void Beans06.setTheColor(java.awt.Color) ==== Events: ==== Event Name: vetoableChange Add Method: public synchronized void Beans06.addVetoableChangeListener( java.beans.VetoableChangeListener) Remove Method: public synchronized void Beans06.removeVetoableChangeListener( java.beans.VetoableChangeListener) Event Type: vetoableChange Event Name: propertyChange Add Method: public synchronized void Beans06.addPropertyChangeListener( java.beans.PropertyChangeListener) Remove Method: public synchronized void Beans06.removePropertyChangeListener( java.beans.PropertyChangeListener) Event Type: propertyChange ==== Methods: ==== makeRed removePropertyChangeListener getTheColor setTheColor removeVetoableChangeListener getPreferredSize addPropertyChangeListener makeBlue addVetoableChangeListener The most significant new addition to this bean class is the ability for a listener to veto a proposed change in the value of a property. When that happens, the proposed new property value is discarded and the actual property value is not changed. The following methods: setTheColor() makeRed() makeBlue() all provide the opportunity for a VetoableChangeListener object to veto a proposed new color value for the property named theColor. Each of these methods receives a proposed new color value as a parameter when it is invoked. The method saves the current value of the property in the instance variable named oldColor. Then it makes a call to the method named notifyVetoableChange() inside a try block. The notifyVetoableChange broadcasts a vetoableChange() event to all of the VetoableChangeListener objects that are registered to receive such an event. Any listener object that wants to veto the change throws a PropertyVetoException which finds its way back to method listed above that invoked notifyVetoableChange() in the first place. When the exception is thrown, it is caught in a catch block. The code in the catch block restores the property value to its original value and displays the exception. In other words, the proposed new value is replaced by the value of the property before the proposed new value was received. This proposed new value then becomes the current value and is used to set the background color of the bean. The proposed new value is also compared with the value of the property before the proposed new value was received. If they are different, meaning that a property change has occurred, the notifyPropertyChange() method is invoked to broadcast a propertyChange() event to all PropertyChangeListener objects registered to receive such an event. An important aspect of the behavior of this bean is based on the use of the fireVetoableChange() method of the VetoableChangeSupport class to actually broadcast the event. A description of this method follows. Pay particular attention to the behavior of the method in the event that someone wants to veto the change. ------ public void fireVetoableChange(String propertyName, Object oldValue, Object newValue) throws PropertyVetoException Report a vetoable property update to any registered listeners. If anyone vetos the change, then fire a new event reverting everyone to the old value and then rethrow the PropertyVetoException. No event is fired if old and new are equal and non-null Parameters: propertyName - The name of the property that was changed. oldValue - The old value of the property. newValue - The new value of the property. Throws: PropertyVetoException if the recipient wishes the property change to be rolled back. //=======================================================// */ import java.awt.event.*; import java.awt.*; import java.io.Serializable; import java.util.*; import java.beans.*; //=======================================================// //All beans should implement the Serializable interface public class Beans06 extends Canvas implements Serializable{ //The following instance variables are used to store the // current property value and a proposed new property // value. protected Color oldColor; protected Color newColor; //The following reference variables are used to access // the list maintenance and event firing capabilities // of the PropertyChangeSupport and VetoableChangeSupport // classes. An object of each of these classes is // instantiated in the constructor. PropertyChangeSupport changeSupportObj; VetoableChangeSupport vetoSupportObj; //-----------------------------------------------------// public Beans06(){//constructor //This bean is a visible square that is initialized to // yellow and can then be changed to red or blue by // invoking methods of the class named makeRed() and // makeBlue(). //The color can be set to any color by invoking the // setTheColor() method and passing a color in as a // parameter. //Initialize the color of the square. newColor = Color.yellow; setBackground(newColor); //Instantiate objects of the support classes to handle // list maintenance and event firing tasks. The // constructor for these support classes requires this // object as the source of the events. changeSupportObj = new PropertyChangeSupport(this); vetoSupportObj = new VetoableChangeSupport(this); }//end constructor //-----------------------------------------------------// //This method defines the preferred display size of the // bean object. public synchronized Dimension getPreferredSize(){ return new Dimension(50,50); }//end getPreferredSize() //-----------------------------------------------------// //This common method is invoked by all three property- // changing methods to process the proposed new color. void processTheColors(){ try{//test to see if anyone vetos the new color notifyVetoableChange("theColor"); }catch(PropertyVetoException exception){ //Someone vetoed the new color. Don't use newColor. newColor = oldColor;// Restore oldColor instead //Display the veto exception System.out.println(exception); }//end catch if(!newColor.equals(oldColor)){//if color changed this.setBackground(newColor);//display new color //notify property listeners of property change notifyPropertyChange("theColor"); }//end if }//end process the colors //-----------------------------------------------------// //The following "set" and "get" methods in conjunction // with the instance variable named oldColor constitute a // property named theColor. public synchronized void setTheColor(Color inColor){ oldColor = newColor;//save current color newColor = inColor;//proposed new color processTheColors();//go process the proposed new color }//end setTheColor() public synchronized Color getTheColor(){ return oldColor; }//end getTheColor //-----------------------------------------------------// //The following two methods are exposed to the builder // tool as accessible methods. public synchronized void makeBlue(){ oldColor = newColor;//save current color newColor = Color.blue;//establish proposed new color processTheColors();//go process the proposed new color }//end makeBlue() public synchronized void makeRed(){ oldColor = newColor;//save current color newColor = Color.red;//establish proposed new color processTheColors();//go process the proposed new color }//end makeRed() //-----------------------------------------------------// //The following two methods are used to maintain a list // of PropertyChangeListener objects who request to be // added to the list or who request to be removed from // the list. //Add a property change listener object to the list. public synchronized void addPropertyChangeListener( PropertyChangeListener listener){ //Pass the task on to the support class method. changeSupportObj.addPropertyChangeListener(listener); }//end addPropertyChangeListener //-----------------------------------------------------// //Remove a property change listener from the list. public synchronized void removePropertyChangeListener( PropertyChangeListener listener){ //Pass the task on to the support class method. changeSupportObj.removePropertyChangeListener(listener); }//end removePropertyChangeListener() //-----------------------------------------------------// //The following two methods are used to maintain a list // of listener objects who request to be registered // as VetoableChangeListener objects, or who request to // be removed from the list. //Add a vetoable change listener object to the list. public synchronized void addVetoableChangeListener( VetoableChangeListener listener){ //Pass the task on to the support class method. vetoSupportObj.addVetoableChangeListener(listener); }//end addVetoableChangeListener //-----------------------------------------------------// //Remove a vetoable change listener from the list. public synchronized void removeVetoableChangeListener( VetoableChangeListener listener){ //Pass the task on to the support class method. vetoSupportObj.removeVetoableChangeListener(listener); }//end removeVetoableChangeListener() //-----------------------------------------------------// //The following method is used to notify listener // objects of changes in the properties. The incoming // parameter is the name of the property that has // changed. Note that this method makes use of the // firePropertyChange() method of an object of the // PropertyChangeSupport class to actually fire the // event. protected void notifyPropertyChange( String changedProperty){ //Pass the task on to the support class method. changeSupportObj.firePropertyChange( changedProperty,oldColor,newColor); }//end notifyPropertyChange() //-----------------------------------------------------// //The following method is used to notify // VetoableChangeListener objects of proposed changes in // the property values. The incoming parameter is the // name of the property that is proposed to be changed. // This method uses the fireVetoableChange() method of // the VetoableChangeSupport class to actually fire the // event. As discussed earlier in this file, the // fireVetoableChange method actually performs some data // processing and does more than simply fire the event. protected void notifyVetoableChange( String vetoableProperty) throws PropertyVetoException{ //Pass the task on to the support class method. vetoSupportObj.fireVetoableChange( vetoableProperty,oldColor,newColor); }//end notifyVetoableChange() }//end class Beans06.java //=======================================================// |
This program has been simplified in an attempt to make it understandable. A more realistic and complex program is provided in the Review section of this lesson.
You will need to refer to the comments in the source code for the Beans06 class to fully understand how this test program works.
The visual manifestation of the Beans06 bean is a colored square. The bean is placed in a Frame object by this test program. The square is initially yellow.
The bean has one property named theColor which controls the color of the square.
Two exposed methods of the bean, makeRed() and makeBlue(), can be invoked to change the color to red or blue.
Invoking the makeRed() or makeBlue() methods changes the value of the property named theColor which in turn changes the color of the square.
You can also change the value of the property named theColor by invoking the setTheColor() method. In this case you can pass in any color as a parameter.
The property named theColor is a bound constrained property. The bean supports a multicast list of PropertyChangeListener objects and also supports a multicast list of VetoableChangeListener objects.
PropertyChangeListener objects are simply notified whenever a change in a property value occurs.
VetoableChangeListener objects are notified of a proposedchange in the property value and have the opportunity to veto the change by raising a PropertyVetoException.
The program begins with the yellow square bean and three Buttons in a Frame on the screen. The buttons are labeled Red, Green, and Blue.
The Red and Blue buttons invoke the makeRed() and makeBlue() methods discussed above.
The Green button invokes the setTheColor() method causing the color green to be passed in as a parameter. Therefore, clicking this button will attempt to change the value of the property named theColor to green.
A listener class is defined which implements both the PropertyChangeListener interface and the VetoableChangeListener interface. As a result, a listener object of this class can register to be notified of proposed property changes with veto authority and can also register to be notified of actual changes.
One such listener object is instantiated and registered to listen for both propertyChange() and vetoableChange() events.
This object is designed to veto any proposal to change the value of the property to green.
Therefore, if you click the Red button, the square will change to red and the following will appear on the screen.
Note the use of the r, g, and b in the square brackets to indicate the contribution of each of these three primary colors to the final color. The maximum contribution of a color is indicated by a value of 255 while a value of 0 indicates no contribution of that primary color.
Note also that both the VetoableChangeListener object and the
PropertyChangeListener object produce output on the screen. Later
we will see that when a proposed change is vetoed, there is no output from
the PropertyChangeListener object, and there are two separate outputs
from the VetoableChangeListener object.
Veto Listener, New property value: java.awt.Color[r=255,g=0,b=0] Change Listener, New property value: java.awt.Color[r=255,g=0,b=0] |
Veto Listener, New property value: java.awt.Color[r=0,g=0,b=255] Change Listener, New property value: java.awt.Color[r=0,g=0,b=255] |
Note that there was no output from the PropertyChangeListener object in this case, because the proposed change to green was vetoed and there was no actual change in the value of the property.
Note also that there are two outputs from the VetoableChangeListener object. The first output indicates the proposed new property value. The second indicates that a second round of events was fired to roll the property value back to its original value.
The last line in the output was produced by code in the bean
proper and was a display of the contents of the exception object that was
instantiated and passed by the listener object that raised the exception
to veto the proposed change.
Veto Listener, New property value: java.awt.Color[r=0,g=255,b=0] Veto Listener, New property value: java.awt.Color[r=0,g=0,b=255] java.beans.PropertyVetoException: No green allowed |
Veto Listener, New property value: java.awt.Color[r=255,g=0,b=0] Change Listener, New property value: java.awt.Color[r=255,g=0,b=0] |
Although this sample program was constructed for simplicity having only one property in the bean and only one listener object, the structure of the Beans06 bean class will support any number of listener objects in either category.
Obviously the number of properties could also be expanded to a very large number.
These expansions would require more processing on the part of the listener objects. With the structure being used, every object registered to be notified of proposed changes would be notified of every proposed change on every property and it may be necessary for the listener objects to differentiate between the properties in order to decide what to do.
Likewise, every object registered to be notified of actual changes would be notified of every actual change on every property.
Each notification event contains the name of the property to which the actual or proposed change applies. The objects could use that information to make decisions on the basis of property names and proposed changes in property values.
Note that the design pattern specifications for Java beans provide for designing more selective notification schemes, but they are not being used in this example.
We're going to skip all the standard stuff that creates the Frame object, adds buttons to the Frame, instantiates listener objects for the buttons, registers the listener objects for actionPerformed() events on the buttons, etc.
However, we will highlight the following code fragment that instantiates
a Beans06 object and adds it to the Frame object.
Beans06 myBean = new Beans06(); add(myBean);//Add it to the Frame |
This dual capability for a single listener object comes about because,
as we will see later, the class of this object named MyPropertyListenerClass
implements both the VetoableChangeListener interface and the PropertyChangeListenerClass.
It also defines both the vetoableChange() and the propertyChange()
methods declared in those two interfaces.
MyPropertyListenerClass myListenerObject = new MyPropertyListenerClass(); myBean.addPropertyChangeListener(myListenerObject); myBean.addVetoableChangeListener(myListenerObject); |
When the setTheColor button is pressed, the object invokes the setTheColor() method on the bean passing in a color parameter of green.
Insofar as the VetoableChangeListener objects are concerned,
this represents a proposal to change the Color property to green.
As mentioned previously, this change will be vetoed, but that is beyond
the scope of the code in this class. As far as the methods in this class
are concerned, this is a direct order to set the property value
of the property named theColor to a value representing green.
class SetTheColorListener implements ActionListener{ Beans06 myBean;//save a reference to the bean here SetTheColorListener(Beans06 inBean){//constructor myBean = inBean;//save a reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.setTheColor(Color.green); }//end actionPerformed() }//end class SetTheColorListener |
When the buttons with the names corresponding to the names of the methods are pressed, these objects invoke methods of the bean under test.
An object of the first class invokes the makeRed() method and an object of the second class invokes the makeBlue() method.
As mentioned earlier, these methods attempt to change the value of the
property named theColor. In the large sense, any of the VetoableChangeListener
objects have the right to veto the proposed change. However, as this test
program is structured, the change to red or blue is not vetoed and the
change will be implemented causing the color of the rectangle on the Frame
object to change colors.
class RedActionListener implements ActionListener{ Beans06 myBean;//save a reference to the bean here RedActionListener(Beans06 inBean){//constructor myBean = inBean;//save the reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.makeRed(); }//end actionPerformed() }//end class RedActionListener //-------------------------------------------------------// class BlueActionListener implements ActionListener{ Beans06 myBean;//save a reference to the bean here BlueActionListener(Beans06 inBean){//constructor myBean = inBean;//save the reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.makeBlue(); }//end actionPerformed() }//end class BlueActionListener |
When one of these objects is registered on the bean as a VetoableChangeListener, it will receive notifications of all the proposed changes to all the constrained properties of the bean. Once notified, the listener object has the right to veto the proposed change by raising a PropertyVetoException.
When one of these objects is registered on the bean as a PropertyChangeListener, it will receive notifications of all actual changes to all of the bound properties of the bean.
When notified of a proposed or actual change, the object displays the actual or proposed new property value.
When notified of a proposed change, the object has the ability to veto the change by raising a PropertyVetoException. The design of this class is such that any proposed change to the color green will be vetoed.
Note that this class implements both the PropertyChangeListener and the VetoableChangeListener interfaces. This makes it possible for a single object of this class to be notified both of proposed changes and actual changes to the properties of the bean.
Note that the constructor for the PropertyVetoException thrown by the vetoableChange() method requires two arguments. The first is a message of type String. The second is the PropertyChangeEvent object that is passed to the method and which is being vetoed.
In other words, the event describing the property change that is being vetoed is encapsulated (along with a message) and sent to the catch block that will eventually process the exception.
Note also that the argument that is passed to the vetoableChange()
method is of type PropertyChangeEvent which is the same type that
is passed to the propertyChange() method. In particular, the incoming
event type is the same for both event handlers, and there is no such thing
as a VetoableChangeEvent tailored to the vetoableChange()
method.
class MyPropertyListenerClass implements PropertyChangeListener,VetoableChangeListener{ public void propertyChange(PropertyChangeEvent event){ //Extract and display the new value System.out.println( "Change Listener, New property value: " + event.getNewValue()); }//end propertyChange() //-----------------------------------------------------// public void vetoableChange(PropertyChangeEvent event) throws PropertyVetoException{ //Extract and display proposed new value System.out.println( "Veto Listener, New property value: " + event.getNewValue()); //Throw an exception on proposed value of green. This // will veto the change. if(event.getNewValue().equals(Color.green)) throw new PropertyVetoException( "No green allowed",event); }//end vetoableChange() }//end MyPropertyListenerClass class |
/*File Beans06Test.java Copyright 1997, R.G.Baldwin This program was designed to be compiled and executed under JDK 1.1.3 or later. This program is designed to test the constrained property aspects of the bean class named Beans06. The program has been simplified as much as possible in an attempt to make it understandable. You will need to refer to the comments in the source code for the Beans06 bean class to fully understand how this test program works. The visual manifestation of the Beans06 bean is a colored square. The bean is placed in a Frame object by this test program. The square is initially yellow. The bean has one property named theColor which controls the color of the square. Two exposed methods of the bean, makeRed() and makeBlue(), can be invoked to change the color to red or blue. Invoking the makeRed() or makeBlue() methods changes the value of the property named theColor which in turn changes the color of the square. You can also change the value of the property named theColor by invoking the setTheColor() method. In this case you can pass in any color as a parameter. The property named theColor is a bound constrained property. The bean supports a multicast list of PropertyChangeListener objects and also supports a multicast list of VetoableChangeListener objects. PropertyChangeListener objects are simply notified whenever a change in a property value occurs. VetoableChangeListener objects are notified of a proposed change in the property value and have the opportunity to veto the change by raising a PropertyVetoException. The program begins with the yellow square bean and three buttons in a frame on the screen. The buttons are labeled Red, Green, and Blue. The Red and Blue buttons invoke the makeRed() and makeBlue() methods discussed above. The Green button invokes the setTheColor() method causing the color green to be passed in as a parameter. Therefore, clicking this button will attempt to change the value of the property named theColor to green. A listener class is defined which implements both the PropertyChangeListener interface and the VetoableChangeListener interface. As a result, a listener object of this class can register to be notified of proposed property changes with veto authority and can also register to be notified of actual changes. One such listener object is instantiated and registered to listen for both propertyChange() and vetoableChange() events. This object is designed to veto any proposal to change the value of the property to green. Therefore, if you click the Red button, the square will turn to red and the following will appear on the screen: Veto Listener, New property value: java.awt.Color[r=255,g=0,b=0] Change Listener, New property value: java.awt.Color[r=255,g=0,b=0] If you click the Blue button, the square will change to blue and the following will appear on the screen. Veto Listener, New property value: java.awt.Color[r=0,g=0,b=255] Change Listener, New property value: java.awt.Color[r=0,g=0,b=255] If you click the Green button, the color of the square will not change. The following will appear on the screen indicating that the proposed new color was vetoed and another event was multicast which rolled the property value back to its value before the proposed change. Veto Listener, New property value: java.awt.Color[r=0,g=255,b=0] Veto Listener, New property value: java.awt.Color[r=0,g=0,b=255] java.beans.PropertyVetoException: No green allowed If you then click on the Red button, the color of the square will change to red and the following will appear on the screen: Veto Listener, New property value: java.awt.Color[r=255,g=0,b=0] Change Listener, New property value: java.awt.Color[r=255,g=0,b=0] In all of the above examples, line breaks were manually inserted in the text to make it fit better in this format. Although this sample program was constructed for simplicity having only one property in the bean and one listener object, the structure of the Beans06 bean class will support any number of listener objects in either category. Obviously the number of properties could also be expanded to a very large number. This would require more processing on the part of the objects. With the structure being used, every object registered to be notified of proposed changes would be notified of every proposed change on every property. Likewise, every object registered to be notified of actual changes would be notified of every actual change on every property. Each notification event contains the name of the property to which the actual or proposed change applies. The objects would have to use that information to make decisions on the basis of property names and proposed changes in property values. =========================================================*/ import java.awt.*; import java.awt.event.*; import java.beans.*; import java.util.*; //=======================================================// public class Beans06Test extends Frame{ public static void main(String[] args){ new Beans06Test(); }//end main //-----------------------------------------------------// public Beans06Test(){//constructor setTitle("Copyright 1997, R.G.Baldwin"); setLayout(new FlowLayout()); //instantiate a Bean object Beans06 myBean = new Beans06(); add(myBean);//Add it to the Frame //Instantiate several test buttons Button buttonToSetTheColor = new Button("Green"); Button buttonToInvokeRedMethod = new Button("Red"); Button buttonToInvokeBlueMethod = new Button("Blue"); //Add the test buttons to the frame add(buttonToInvokeRedMethod); add(buttonToSetTheColor); add(buttonToInvokeBlueMethod); //Size the frame and make it visible setSize(250,350); setVisible(true); //Register action listener objects for all the test // buttons buttonToSetTheColor.addActionListener( new SetTheColorListener(myBean)); buttonToInvokeRedMethod.addActionListener( new RedActionListener(myBean)); buttonToInvokeBlueMethod.addActionListener( new BlueActionListener(myBean)); //Instantiate and register an object to listen for // proposed and actual changes in the bean's property. // This listener object has the ability to veto // proposed changes. MyPropertyListenerClass myListenerObject = new MyPropertyListenerClass(); myBean.addPropertyChangeListener(myListenerObject); myBean.addVetoableChangeListener(myListenerObject); //Terminate program when Frame is closed this.addWindowListener(new Terminate()); }//end constructor }//end class Beans06Test //=======================================================// //An object of this class is instantiated and registered // to listen for actionPerformed() events on the button // labeled "setTheColor". // When the setTheColor button is pressed, the object // invokes the setTheColor() method on the bean passing in // a color parameter of green. class SetTheColorListener implements ActionListener{ Beans06 myBean;//save a reference to the bean here SetTheColorListener(Beans06 inBean){//constructor myBean = inBean;//save a reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.setTheColor(Color.green); }//end actionPerformed() }//end class SetTheColorListener //-------------------------------------------------------// //The following two classes are used to instantiate objects // which are registered to listen to two of the buttons on // the test panel. When the corresponding buttons are // pressed, these objects invoke methods of the bean under // test. The first class invokes the makeRed() method and // the second class invokes the makeBlue() method. class RedActionListener implements ActionListener{ Beans06 myBean;//save a reference to the bean here RedActionListener(Beans06 inBean){//constructor myBean = inBean;//save the reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.makeRed(); }//end actionPerformed() }//end class RedActionListener //-------------------------------------------------------// class BlueActionListener implements ActionListener{ Beans06 myBean;//save a reference to the bean here BlueActionListener(Beans06 inBean){//constructor myBean = inBean;//save the reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.makeBlue(); }//end actionPerformed() }//end class BlueActionListener //=======================================================// //The following class is used to instantiate objects that // will be bound to the bean in such a way as to be // notified of proposed changes and actual changes in the // property values in the bean object. //When notified of a proposed or actual change, the object // displays the actual or proposed new property value. //When notified of a proposed change, the object has the // ability to veto the change by raising a // PropertyVetoException. The design of this class is // such that any proposed change to the color green will // vetoed. class MyPropertyListenerClass implements PropertyChangeListener,VetoableChangeListener{ public void propertyChange(PropertyChangeEvent event){ //Extract and display the new value System.out.println( "Change Listener, New property value: " + event.getNewValue()); }//end propertyChange() public void vetoableChange(PropertyChangeEvent event) throws PropertyVetoException{ //Extract and display proposed new value System.out.println( "Veto Listener, New property value: " + event.getNewValue()); //Throw an exception on proposed value of green. This // will veto the change. if(event.getNewValue().equals(Color.green)) throw new PropertyVetoException( "No green allowed",event); }//end vetoableChange() }//end MyPropertyListenerClass class //=======================================================// class Terminate extends WindowAdapter{ public void windowClosing(WindowEvent e){ //terminate the program when the window is closed System.exit(0); }//end windowClosing }//end class Terminate //=======================================================// |
Cause your bean to appear on the screen as a colored rectangle containing a date and time. Provide a Color property to control the background color of the rectangle. Provide a Date property to control the date and time that is displayed in the rectangle. Make both of the properties bound and constrained.
Design one of your VetoableChangeListener objects to veto proposed property changes which would otherwise cause the rectangle to be green. Design the other VetoableChangeListener object to veto proposed property changes that would cause the rectangle to be orange. Demonstrate that other colors are allowed.
Provide buttons on your test panel which will attempt to cause the color of the rectangle to be red, green, blue, or orange.
Also provide a button on your test panel that will set the current date and time in the Date property.
Provide an output on the standard output device whenever the colors green or orange are vetoed, identifying the reason for the veto and the object that raised the veto.
Provide an output on the standard output device whenever the value of a property actually changes, identifying the new value of the property, and the identification of the listener object that recognized the change.
A - See the following bean program and test program.
Bean program follows:
/*File Beans07.java Copyright 1997, R.G.Baldwin This program was designed to be compiled and executed under JDK 1.1.3 or later. This program illustrates the use of beans with multiple properties which are both bound and constrained. This bean appears on the screen as a colored rectangle containing a date and time. The color as well as the date and time are based on the current values of corresponding properties. The bean has a Color property named theColor and a Date property named theDate. Both of these properties are bound and constrained. The bean has a property named preferredSize that is neither bound nor constrained This bean supports propertyChange and vetoableChange notification lists for the property values. Other objects can register to be notified of a proposed change in property values and can veto the change. A proposed change that is vetoed does not take place. Other objects can also register to be notified of actual changes in property values. A description of the bean as determined by the program named Introspect01 follows: ------- Name of bean: Beans07 Class of bean: class Beans07 ==== Properties: ==== Name: preferredSize Type: class java.awt.Dimension Get method: public synchronized java.awt.Dimension Beans07.getPreferredSize() Set method: null Name: theDate Type: class java.util.Date Get method: null Set method: public synchronized void Beans07.setTheDate(java.util.Date) Name: theColor Type: class java.awt.Color Get method: null Set method: public synchronized void Beans07.setTheColor(java.awt.Color) ==== Events: ==== Event Name: vetoableChange Add Method: public synchronized void Beans07.addVetoableChangeListener( java.beans.VetoableChangeListener) Remove Method: public synchronized void Beans07.removeVetoableChangeListener( java.beans.VetoableChangeListener) Event Type: vetoableChange Event Name: propertyChange Add Method: public synchronized void Beans07.addPropertyChangeListener( java.beans.PropertyChangeListener) Remove Method: public synchronized void Beans07.removePropertyChangeListener( java.beans.PropertyChangeListener) Event Type: propertyChange ==== Methods: ==== setTheDate removePropertyChangeListener setTheColor removeVetoableChangeListener getPreferredSize addPropertyChangeListener addVetoableChangeListener ------- The following methods: setTheColor() setTheDate() both provide the opportunity for a VetoableChangeListener object to veto a proposed new value for the property. Each of these methods receives a proposed property value as a parameter when it is invoked. The method saves the current value of the property in an instance variable named old_____. Then it makes a call to the method named notifyVetoableChange() inside a try block. notifyVetoableChange() broadcasts a vetoableChange() event to all of the VetoableChangeListener objects that are registered to receive such an event. Any listener object that wants to veto the change throws a PropertyVetoException which finds its way back to the method listed above that invoked notifyVetoableChange() in the first place. When the exception is thrown, it is caught in a catch block. The code in the catch block restores the property value to its original value. In other words, theproposed new value is discarded and replaced by the value of the property before the proposed new value was received. This proposed new value then becomes the current value and is used to set the background color of the bean or to set the new date and time. The proposed new value is also compared with the value of the property before the proposed new value was received. If they are different, meaning that a property change has occurred, the notifyPropertyChange() method is invoked to broadcase a propertyChange() event to all PropertyChangeListener objects registered to receive such an event. An important aspect of the behavior of this bean is based on the use of the fireVetoableChange() method of the VetoableChangeSupport class to actually broadcast the event. A description of this method follows. Note in particular the behavior of this method when someone vetos the change. ------ public void fireVetoableChange(String propertyName, Object oldValue, Object newValue) throws PropertyVetoException Report a vetoable property update to any registered listeners. If anyone vetos the change, then fire a new event reverting everyone to the old value and then rethrow the PropertyVetoException. No event is fired if old and new are equal and non-null Parameters: propertyName - The name of the property that was changed. oldValue - The old value of the property. newValue - The new value of the property. Throws: PropertyVetoException if the recipient wishes the property change to be rolled back. Additional comments describing the bean are scattered throughout the code. This bean was tested using the test program named Beans07Test using JDK 1.1.3 under Win95. //=======================================================// */ import java.awt.event.*; import java.awt.*; import java.io.Serializable; import java.util.*; import java.beans.*; //=======================================================// //All beans should implement the Serializable interface public class Beans07 extends Label implements Serializable{ //The following instance variables are used to store the // current property value and proposed new property // value for both the Color and Date properties. protected Color oldColor; protected Color newColor; protected Date oldDate; protected Date newDate; //The following reference variables are used to access // the list maintenance and event firing capabilities // of the PropertyChangeSupport and VetoableChangeSupport // classs. An object of each of these classes is // instantiated in the constructor. PropertyChangeSupport changeSupportObj; VetoableChangeSupport vetoSupportObj; //-----------------------------------------------------// public Beans07(){//constructor //Initialize the property values and the display newColor = Color.yellow; setBackground(newColor); newDate = new Date(); setText(newDate.toString()); //Instantiate objects of the support classes to handle // list maintenance and event firing tasks. The // constructor for the support classes requires this // object as a paremeter. The parameter is used as the // source of the events when they are fired. changeSupportObj = new PropertyChangeSupport(this); vetoSupportObj = new VetoableChangeSupport(this); }//end constructor //-----------------------------------------------------// //This method defines the preferred display size of the // bean object. public synchronized Dimension getPreferredSize(){ return new Dimension(200,50); }//end getPreferredSize() //-----------------------------------------------------// //The following "set" method in conjunction with the // instance variables named oldColor and newColor // constitute a write-only property named theColor. public synchronized void setTheColor(Color inColor){ oldColor = newColor;//save current color newColor = inColor;//proposed new color try{//test to see if anyone vetos the new color notifyVetoableChange("theColor"); }catch(PropertyVetoException exception){ //Someone vetoed the new color. Don't use newColor. newColor = oldColor;// Restore oldColor instead }//end catch if(!newColor.equals(oldColor)){//if color changed this.setBackground(newColor);//display new color //notify property listeners of property change notifyPropertyChange("theColor"); }//end if }//end setTheColor() //-----------------------------------------------------// //The following "set" method in conjunction with the // instance variables named oldDate and newDate // constitute a write-only property named theDate. public synchronized void setTheDate(Date inDate){ oldDate = newDate;//save current date newDate = inDate;//proposed new date try{//test to see if anyone vetos the new date notifyVetoableChange("theDate"); }catch(PropertyVetoException exception){ //Someone vetoed the new date. Don't use newDate. newDate = oldDate;// Restore oldDate instead //Display the veto exception System.out.println(exception.getMessage()); }//end catch if(!newDate.equals(oldDate)){//if date changed this.setText(newDate.toString());//display new date //notify property listeners of property change notifyPropertyChange("theDate"); }//end if }//end setTheColor() //-----------------------------------------------------// //The following two methods are used to maintain a list // of listener objects who request to be registered as // PropertyChangeListener objects, or who request to be // removed from the list. //Add a property change listener object to the list. public synchronized void addPropertyChangeListener( PropertyChangeListener listener){ //Pass the task to the support class. changeSupportObj.addPropertyChangeListener(listener); }//end addPropertyChangeListener //-----------------------------------------------------// //Remove a property change listener from the list. public synchronized void removePropertyChangeListener( PropertyChangeListener listener){ //Pass the task to the support class. changeSupportObj. removePropertyChangeListener(listener); }//end removePropertyChangeListener() //-----------------------------------------------------// //The following two methods are used to maintain a list // of listener objects who request to be registered // as VetoableChangeListener objects, or who request to // be removed from the list. //Add a vetoable change listener object to the list. public synchronized void addVetoableChangeListener( VetoableChangeListener listener){ //Pass the task to the support class. vetoSupportObj.addVetoableChangeListener(listener); }//end addVetoableChangeListener //-----------------------------------------------------// //Remove a vetoable change listener from the list. public synchronized void removeVetoableChangeListener( VetoableChangeListener listener){ //Pass the task to the support class. vetoSupportObj.removeVetoableChangeListener(listener); }//end removeVetoableChangeListener() //-----------------------------------------------------// //The following method is used to notify // PropertyChangeListener objects of changes in the // properties. The incoming parameter is the name of the // property that has changed. protected void notifyPropertyChange( String changedProperty){ if(changedProperty.compareTo("theColor") == 0) //TheColor property has changed, pass color info changeSupportObj.firePropertyChange( changedProperty,oldColor,newColor); else //TheDate property has changed, pass date info changeSupportObj.firePropertyChange( changedProperty,oldDate,newDate); }//end notifyPropertyChange() //-----------------------------------------------------// //The following method is used to notify // VetoableChangeListener objects of proposed changes in // the property values. The incoming parameter is the // name of the property that is proposed to be changed. // This method uses the fireVetoableChange() method of // the VetoableChangeSupport class to actually fire the // event. As discussed earlier in this file, the // fireVetoableChange method actually performs some data // processing and does more than simply fire the event. // In the event of a veto, it fires a second event with // the value of the property that existed prior to the // proposed change. protected void notifyVetoableChange( String vetoableProperty) throws PropertyVetoException{ if(vetoableProperty.compareTo("theColor") == 0) //theColor property is proposed to be changed vetoSupportObj.fireVetoableChange( vetoableProperty,oldColor,newColor); else //theDate property is proposed to be changed vetoSupportObj.fireVetoableChange( vetoableProperty,oldDate,newDate); }//end notifyVetoableChange() }//end class Beans07.java //=======================================================// |
/*File Beans07Test.java Copyright 1997, R.G.Baldwin This program was designed to be compiled and executed under JDK 1.1.3 or later. This program is designed to test the constrained property aspects of the bean class named Beans07 for multiple properties and multiple listener objects. You will need to refer to the comments in the source code for the Beans07 bean class to fully understand how this test program works. The visual manifestation of the Beans07 bean is a colored rectangle with a date and time displayed in the rectangle. The bean is placed in a Frame object by this test program. The rectangle is initially yellow. The bean has two bound and constrained properties named theColor and theDate which control the color of the rectangle and the date and time displayed in the rectangle. You can change the color of the rectangle by invoking the setTheColor() method on the bean and passing in a Color as a parameter. You can change the date and time displayed in the rectangle by invoking the setTheDate() method on the bean and passing a Date object as a parameter. The bean supports a multicast list of PropertyChangeListener objects and also supports a multicast list of VetoableChangeListener objects for both of the bound and constrained properties. PropertyChangeListener objects are simply notified whenever a change in a property value occurs. VetoableChangeListener objects are notified of a proposed change in the property value and have the opportunity to veto the change by raising a PropertyVetoException. This program begins with a yellow rectangular bean containing a date and time along with five buttons in a frame on the screen. The buttons are labeled Red, Green, Blue, Orange, and Date. Clicking one of the buttons with a color label causes the setTheColor() method to be invoked on the bean with the indicated color being passed in as a parameter. Clicking the date button causes the setTheDate() method to be invoked on the bean, passing in a Date object containing the current date and time. A listener class is defined which implements both the PropertyChangeListener interface and the VetoableChangeListener interface. As a result, a listener object of this class can register to be notified of proposed property changes with veto authority and can also register to be notified of actual changes. The constructor for this listener class also allows a String object and a Color value to be passed in as a parameter. The String object is used as an identifier when information about the listener object is displayed. The Color value is used to establish a color that will be vetoed by the listener object. Two such listener objects are instantiated and registered to listen for both propertyChange() and vetoableChange() events. One object is named Joe and will veto attempts to change the Color property to green. The other object is named Tom and will veto attempts to change the Color property to orange. If you click the Red button, the rectangle will change to red and the following will appear on the screen: Joe Change Listener New property value: java.awt.Color[r=255,g=0,b=0] Tom Change Listener New property value: java.awt.Color[r=255,g=0,b=0] If you click the Green button, the color of the rectangle will not change. The following will appear on the screen indicating that the proposed new color was vetoed. Joe vetos java.awt.Color[r=0,g=255,b=0] If you click the Blue button, the rectangle will change to blue and the following will appear on the screen. Joe Change Listener New property value: java.awt.Color[r=0,g=0,b=255] Tom Change Listener New property value: java.awt.Color[r=0,g=0,b=255] If you click the Orange button, the color of the rectangle will not change. The following will appear on the screen indicating that the proposed new color was vetoed. Tom vetos java.awt.Color[r=255,g=200,b=0] If you then click on the Red button, the color of the rectangle will change to red and the following will appear on the screen: Joe Change Listener New property value: java.awt.Color[r=255,g=0,b=0] Tom Change Listener New property value: java.awt.Color[r=255,g=0,b=0] If you click on the Date button, the new date and time will appear in the colored rectangle and the following will appear on the screen: Joe Change Listener New property value: Sun Oct 19 15:14:07 CDT 1997 Tom Change Listener New property value: Sun Oct 19 15:14:07 CDT 1997 =========================================================*/ import java.awt.*; import java.awt.event.*; import java.beans.*; import java.util.*; //=======================================================// public class Beans07Test extends Frame{ public static void main(String[] args){ new Beans07Test(); }//end main //-----------------------------------------------------// public Beans07Test(){//constructor setTitle("Copyright 1997, R.G.Baldwin"); setLayout(new FlowLayout()); //instantiate a Bean object Beans07 myBean = new Beans07(); add(myBean);//Add it to the Frame //Instantiate several test buttons Button buttonToSetToGreen = new Button("Green"); Button buttonToSetToRed = new Button("Red"); Button buttonToSetToBlue = new Button("Blue"); Button buttonToSetToOrange = new Button("Orange"); Button buttonToSetTheDate = new Button("Date"); //Add the test buttons to the frame add(buttonToSetToRed); add(buttonToSetToGreen); add(buttonToSetToBlue); add(buttonToSetToOrange); add(buttonToSetTheDate); //Size the frame and make it visible setSize(250,350); setVisible(true); //Register action listener objects for all the test // buttons buttonToSetToGreen.addActionListener( new SetTheColorListener(myBean,Color.green)); buttonToSetToRed.addActionListener( new SetTheColorListener(myBean,Color.red)); buttonToSetToBlue.addActionListener( new SetTheColorListener(myBean,Color.blue)); buttonToSetToOrange.addActionListener( new SetTheColorListener(myBean,Color.orange)); buttonToSetTheDate.addActionListener( new SetTheDateListener(myBean)); //Instantiate and register objects to listen for // proposed and actual changes in the bean's property // values. These listener objects havethe ability to // veto proposed changes. //This object is named Joe and vetos the green color MyPropertyListenerClass joeListenerObject = new MyPropertyListenerClass("Joe",Color.green); myBean.addPropertyChangeListener(joeListenerObject); myBean.addVetoableChangeListener(joeListenerObject); //This object is named Tom and vetos the orange color MyPropertyListenerClass tomListenerObject = new MyPropertyListenerClass("Tom",Color.orange); myBean.addPropertyChangeListener(tomListenerObject); myBean.addVetoableChangeListener(tomListenerObject); //Terminate program when Frame is closed this.addWindowListener(new Terminate()); }//end constructor }//end class Beans07Test //=======================================================// //An object of this class will invoke the setTheColor() // method on the bean passing a specified color as a // parameter. The specified color is passed as a parameter // to the constructor of this class. class SetTheColorListener implements ActionListener{ Beans07 myBean;//save a reference to the bean here Color colorToSet;//save the new color here //constructor SetTheColorListener(Beans07 inBean,Color inColor){ myBean = inBean;//save a reference to the bean colorToSet = inColor;//save the new color }//end constructor public void actionPerformed(ActionEvent e){ myBean.setTheColor(colorToSet); }//end actionPerformed() }//end class SetTheColorListener //=======================================================// //An object of this class will invoke the setTheDate() // method on the bean passing a Date object as a parameter. // The date object is constructed to contain the current // date and time. class SetTheDateListener implements ActionListener{ Beans07 myBean;//save a reference to the bean here //constructor SetTheDateListener(Beans07 inBean){ myBean = inBean;//save a reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.setTheDate(new Date()); }//end actionPerformed() }//end class SetTheDateListener //=======================================================// //The following class is used to instantiate objects that // will be bound to the bean in such a way as to be // notified of proposed changes and actual changes in the // property values in the bean object. //When notified of a proposed or actual change, the object // displays the actual or proposed new property value. //When notified of a proposed change, the object has the // ability to veto the change by raising a // PropertyVetoException. //The constructor for this class accepts a String object // and a Color parameter as incoming parameters. The // String is used to identify the object when information // is displayed. The Color parameter specifies a color // that will be vetoed by the object if an attempt is // made to change the Color property of the bean to that // Color value. //Note that this class implements PropertyChangeListener // and VetoableChangeListener class MyPropertyListenerClass implements PropertyChangeListener,VetoableChangeListener{ String objID; //store the object ID here Color vetoColor; //store the color to be vetoed here //constructor MyPropertyListenerClass(String idIn,Color vetoColorIn){ objID = idIn;//save the object ID vetoColor = vetoColorIn;//save the veto color }//end constructor public void propertyChange(PropertyChangeEvent event){ //Extract and display the new value System.out.println( objID + " Change Listener\n New property value: " + event.getNewValue()); }//end propertyChange() public void vetoableChange(PropertyChangeEvent event) throws PropertyVetoException{ if(event.getNewValue() == vetoColor){//test for veto System.out.println( objID + " vetos " + event.getNewValue()); //Throw an exception on proposed change. This will // veto the change. throw new PropertyVetoException("VETO",event); }//end if }//end vetoableChange() }//end MyPropertyListenerClass class //=======================================================// class Terminate extends WindowAdapter{ public void windowClosing(WindowEvent e){ //terminate the program when the window is closed System.exit(0); }//end windowClosing }//end class Terminate //=======================================================// |
-end-