Document last modified:
Components are generally defined as self-contained software that follow a specific interface protocol that allows communication with other components. JavaBeans are Java objects that follow a specific interface protocol for communicating with other Java objects. Advantages of components can be illustrated by the following example.
Two objects, a tick object that notifies for each minute ticked and a counter object that counts each time notified can be connected to create a clock.
Suppose the tick and counter are available as regular Java objects. The programmer would need to know precisely how the tick notified that the tick event had occurred and what method was used for counter counting in order to connect the tick notification to the count. The programmer would also need to write some Java code to, in effect, glue the tick and counter object together. In contrast, a tick and counter component that follow the standard JavaBean protocol can expose events and properties used to communicate the tick event notification to the counter. The programmer would not need to know much about either the tick or counter object, in fact, because of the component interface standardization, the glue code could be generated automatically. Using a graphical programming environment, we'll see that components can be combined by connecting from one component output method to the input of a component input method.
Generally the JavaBean component protocol consists of:
|
While Java objects can be developed using the JDK (Java Development Kit), JavaBean components can be developed graphically using the BDK (Bean Development Kit), Sun NetBeans, Borland JBuilder. The BDK includes a graphical environment called the BeanBox in which components can be connected together graphically and tested. NetBeans provides a complete development environment for Java and JavaBeans and will be used in the following. A number of sample JavaBeans are provided to allow experimentation with components.
We'd like to connect a keypad to a display without knowing much of how either works. Whenever the keypad gets a new digit, the display should automatically receive the digit.
Two component classes:
- Keypad - Has a property, a single digit. When digit (property) changes, any users of that property are notified.
- Display - Notified when a property to which it is listening changes.
Components are connected in the main class.
From the point of view of our Example class, the keypad connects to the display by calling:
keypad.addDigitListener( display );
Calling the keypad method setDigit changes the digit on the keypad and, since we connected the keypad and display, also sends the digit to the display.
In the following:
Question - What is the effect of three: keypad.addDigitListener( display ); ?
|
Example
|
| public class Example { public static void main(String a[]) { KeyPad keypad=new KeyPad(); Display display=new Display(); keypad.addDigitListener( display ); // Connect source to listener keypad.setDigit("0"); keypad.setDigit("1"); keypad.setDigit("2"); } } |
import java.beans.*; public class Display implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent e) { System.out.println( "Display "+ e.getNewValue() ); } } |
| import java.beans.*; public class KeyPad { private PropertyChangeSupport pcDigit = new PropertyChangeSupport(this); private String digit=null; public void addDigitListener(PropertyChangeListener l) { pcDigit.addPropertyChangeListener(l); } public void setDigit(String newDigit) { String oldDigit = this.digit; this.digit=newDigit; pcDigit.firePropertyChange("digit", oldDigit, newDigit); } } |
Execution Display 0 Display 1 Display 2 |

Communication with bound objects
KeyPad uses property change notification of any registered listeners whenever the digit property changes.
The essentials of property change notification are:
- An object must register with the property owner object for notification of changes to the property.
public void addDigitListener(PropertyChangeListener l) {
pcDigit.addPropertyChangeListener(l);
}- The property owner builds a list of registered listener objects.
- When the property changes, the owner notifies all objects on the registration list of the new property value.
pcDigit.firePropertyChange ("digit", oldDigit, newDigit ); Display implements PropertyChangeListener
Means that is agrees to define a method with signature:
public void propertyChange(PropertyChangeEvent e)
to be called by firePropertyChange whenenver the "digit" value is changed.
Example has two objects:
- keypad - a bound property (object) meaning it can register and notify listeners.
- display - an object that must be notified by the keypad whenever changes occur.
Bound Properties
Properties can report when changed to listeners with the same property type (String, float, etc.). The change is normally reported to listeners by calling the
listener's set property method. By connecting a bound property in one bean to a property (bound or not) in another bean, both properties can be updated simultaneously to the same value. Beans with bound properties can also generate an event when a property changes, involving a public method in a bean when the property changes. A bound property requires a method for registering listeners to be notified that the bound property changed (addDigitListener).
To notify listeners, the method firePropertyChange is called with three parameters, a string defining the name of the bound property, the bound property old value and new value. If old ¹ new value the property listener is notified of the change.
While simple to use, PropertyChangeListeners are limited.
For example, it gets a little messy when listening to more than one property change at a time, requiring the listener to know and examine the source of the property.
We'll now start at the beginning of component communication by first examining a non-component approach to handling external events, then compare with components.
The first step in handling an event is determining what caused the event.
With a calculator button click, one can check each possible button case by the button text label, as illustrated at left below. When the Hit me button receives the action clicked an event is passed to the action method where it is examined to determine which event and which button was acted on by comparing the label. As we saw in Homework 6 and the Calculator, handling a large number of button events can get messy.
![]() import java.applet.*; import java.awt.*; public class ButtonApplet extends Applet {
add(button);
return true;
ButtonApplet.htm
|
![]()
import java.applet.*; public class ButtonApplet extends Applet {
add(button);
|

Obviously in a GUI with many buttons, sliders, etc. that each generates multiple events, a single action method would be very complicated, needing to check the event against every possible case. A more scalable approach is to define an individual handler or listener for each event as in the example at right above. Buttons define the single ActionEvent event which must be connected to the listener code that handles the event.
One approach is to define a listener class for each type of event, in the example the ActionEvent listener is implemented in the ButtonListener class.
Because ButtonListener implements
ActionListener it must define the actionPerformed method which is
invoked whenever the ActionEvent occurs. The ButtonListener object
bl must be registered as a listener with the button.
Naming conventions
Below is the Java Class Library documentation on MouseListener:
Interface MouseListener
The listener interface for receiving "interesting" mouse events (press, release, click, enter, and exit) on a component. (To track mouse moves and mouse drags, use the MouseMotionListener.) The class that is interested in processing a mouse event either
implements this interface (and all the methods it contains) or extends
the abstract The listener object created from that class is then registered with a
component using the component's
|
||||||||||||
Exercise 1 - Event listeners and adapters follow a naming
convention where:
defines the method to register a listener with a component. An interface is defined as:
and event methods and classes are defined as:
For example, the mouse is:
void addMouseListener( MouseListener object) |
Inner classes
Writing a new listener class just to implement the event handling method (e.g. actionPerformed) is tedious, clutters the name space, and is error prone. One simplification is inner classes or classes that are defined in the scope of another class. The following defines at right an anonymous inner class to listen for the ActionEvent of the Button. At left is the code used earlier.
| buttonListener bl = new buttonListener(button); button.addActionListener(bl); class buttonListener implements ActionListener { |
button.addActionListener(new ActionListener( ) { public void actionPerformed(ActionEvent e) { button.setLabel("Ouch"); } } ); |
![]()
import java.applet.*; public class ButtonApplet extends Applet {
add(button);
|
![]()
import java.applet.*; public class ButtonApplet extends Applet {
add(button); |
Exercise 2 - Implement the inner-class for Exercise 1, given
again below.
|
Recall from Homework 6 the Calculator; at left is the basic calculator using inner-class to define the event handler, at right is the calculator with a switch statement to determine the appropriate action.
| public class Calculator extends Applet { public Calculator() { Button button1 = new Button("1"), buttonequal = new Button("="), buttonplus = new Button("+");
|
public class Calculator extends UserInterface
{ public Calculator() { addButton("1"); addButton("+"); addButton("="); }
|
Creating individual handlers for each button of a calculator can be automated.
A more extensible approach creates 10 digit buttons and a handler for each, see makeDigitButton(int n).
| public class Calculator extends Applet { private TextField display; private Panel keypad; public Calculator() { Button buttonequal = new Button("="), buttonplus = new Button("+"); buttonequal.addActionListener(new ActionListener( ) { public void actionPerformed(ActionEvent e) { equal(); } } ); buttonplus.addActionListener(new ActionListener( ) { public void actionPerformed(ActionEvent e) { setOperation('+'); setOperand(accumulator); setAccumulator(0.0); } } ); keypad = new Panel(); for (int i=0; i<=9; i++) makeDigitButton(i); keypad.add(buttonplus); keypad.add(buttonequal); }
|
A JavaBean is a regular, programmer defined Java class that follows a standard protocol for naming methods that access internal attributes (properties) and for event notification. By following the protocol, other JavaBeans or programs can interact with a JavaBean through the standard interface. One key advantage is that the JavaBean is self-contained, communication is restricted through the consistently named protocol methods. This allows JavaBeans to implement large, independent components such as a word processor or graphing component or small components such as buttons that can communicate with other independent components. The component can be integrated into an application more easily than a class, often with little or no programming.
One obvious part of the naming protocol defines mutator methods for setting and accessor methods for getting the values of JavaBean class attributes.
In the Counter bean, the maxValue attribute has two methods, the accessor and mutator methods of:
| setMaxValue getMaxValue |
Sets the value of attribute maxValue; a mutator method
Gets the value of attribute maxValue; an accessor method |
Example
The following illustrates the naming protocol for property maxValue and that the protocol can be ignored for property count. We'll try to do better but need to keep things simple.
The above Button example has been modified to increment a Counter bean by calling an increment() method (mutator) whenever a button actionPerformed event is generated, the button is clicked. The counter displays the counter value in blue. The changes to the ButtonApplet are modest and highlighted below.
ButtonApplet2
public class ButtonApplet2 extends Applet { button.addActionListener(new ActionListener( ) {
}
add(button);
|
Counter import java.awt.*; public class Counter extends Panel {
public Counter() { public void increment () {
|
JavaBean Events Example
JavaBeans have at a minimum four parts for event xxx:
void addxxxListener( xxxListener object)
xxxListener
xxxEvent
void xxxEventhandler( xxxEvent e )
We have seen that JavaBean events and event handlers conform to a protocol of naming conventions. The following example illustrates the protocol more fully by defining events and event handlers for counter values that exceed the maximum value. The example is based on one in Essential JavaBeans Fast. It defines two JavaBeans, a Counter and Alarm bean, and two regular classes for the event (MaxValueEvent) and event listener (MaxValueListener).
Note in the following that the Counter and Alarm definitions are not explicitly connected.
Counter - Implements a visual counter that triggers an event whenever the counter exceeds a defined value. The MaxValueReached event is then sent to all registered MaxValueListeners by calling their maxValueReached method. Attributes (properties) maxValue can be examined and modified externally by calling methods to setMaxValue or getMaxValue the property.
The addMaxValueListener and removeMaxValueListener methods register/unregister listeners that are to be notified when a MaxValueEvent occurs. In this example only one listener can be registered, normally multiple listeners could be registered and be notified of the same event by managing a list of listeners.
MaxValueEvent - Defines the MaxValueEvent, inherits from the Java EventObject class. The MaxValueEvent constructor calls the parent class constructor.
MaxValueListener - An interface class. That means that it is incomplete or abstract, only defines the methods that must be completed by a class that actually completes or implements the MaxValueListener class. Inherits from Java EventListener.
Alarm - Implements MaxValueListener interface by defining the maxValueReached method called by the Counter bean whenever the counter exceeds a defined value.
|
|
Note in the following that the Counter and Alarm definitions are not explicitly connected. But the two can be connected through the listener notification by:
| counter.addMaxValueListener(alarm); // Connects counter event to alarm listener |
However, a Counter object can notify a MaxValueListener that a MaxValueEvent has occurred.
The Alarm implements MaxValueListener so must implement the maxValueReached method, which changes the background to red.
In the following applet the 1) button ActionEvent executes the counter.increment() method; 2) the counter.increment() method notifies all MaxValueListener such as alarm of the MaxValueReachedEvent. The alarm changes the background to red.
![]() import java.applet.*; import java.awt.*; import java.awt.event.*; import counterEvent.Alarm; import counterEvent.Counter; public class ButtonApplet extends Applet { public void init() { button.addActionListener(new
ActionListener( ) {
add(button); // Add button, counter and
alarm objects to applet |
Running the example - The ButtonApplet uses classes grouped into the counterEvent package; which must occupy a subdirectory counterEvent below ButtonApplet.java location.
|
| Exercise 3
The Alarm class implements the MaxValueListener interface requiring a maxValueReached method to be implemented as part of the interface specifications. Changing the Alarm class to that below and using an inner-class in the ButtonApplet above accomplishes the same results without requiring the Alarm class to incorporate any information about the MaxValueListener.
Question Give the inner-class for ButtonApplet that accomplishes the same results as:
Answer
Note - The downside is that the user must know more about the Alarm object. For example, the interfacing details to the setBackground() method. |
Beans that are used as a group can be placed together into a jar file, essentially a library of classes; the classes defined earlier will be jarr'ed and used later in the following examples. The steps to creating a jar with the above beans are:
| Name: MaxValueListener.class Java-Bean: False Name: MaxValueEvent.class Name: Counter.class Name: Alarm.class |
Some development environments automate the definition of inner-class event adapters. The following illustrates how it can be used to remove the programming of inner-class event adapters.
At Home:
Download NetBeans.
At IUS or Home: Find
in the Programs
menu or on the desktop.

Previous examples illustrated how events generated by clicking the mouse could be connected to a listener method by manually writing code such as:
button.addActionListener(new ActionListener( ) {
public void actionPerformed(ActionEvent e) {
counter.increment();
}
}
);
NetBeans and other Java development environments can automatically generate the code needed to connect events and listeners. First connect the JButton event actionPerformed with the Counter increment( ) method.
| private void
jButton1ActionPerformed(java.awt.event.ActionEvent evt) { counter1.increment(); } |
The Counter generates an event that can be connected to the Alarm maxValueReached( ) method. Connect the Counter event maxValue with the Alarm method maxValueReached.
private void counter1MaxValueReached(counterEvent.MaxValueEvent evt) {
alarm1.setBackground(java.awt.Color.red);
}
We have seen that events serve to connect object behavior. Standardization for naming event and listener classes and registration methods are meant to provide the programmer with useful information on the purpose of each; recall:
void addxxxListener( xxxListener object)
xxxListener
xxxEvent
void xxxEventhandler( xxxEvent e )
You may also recall that when constructing a application using beans, the programmer still needed to supply these names; implying there was not sufficient information available for the IDE to figure out how things should be connected. Ideally, the component could provide enough information to an application (e.g. IDE) that connections between objects could be established without programmer involvement; part of the solution in Java is to use bound properties.
The Counter will be modified to use property change notification rather than events. The essentials of property change notification are:
| public void addCounterListener(PropertyChangeListener
l) { pcsupport.addPropertyChangeListener(l); } |
| pcsupport.firePropertyChange ("count", new Integer(oldcount), new Integer(count)); |
The Counter bean example is modified in three ways:
Bound Properties - Properties can report when changed to listeners
with the same property type (String, float, etc.). The change is normally
reported to listeners by calling the
listener's set property method. By
connecting a bound property in one bean to a property (bound or not) in another
bean, both properties can be updated simultaneously to the same value. Beans
with bound properties can also generate an event when a property changes,
involving a public method in a bean when the property changes. A bound property
requires two methods, (addCounterListener and
removeCounterListener) one for registering listeners to be notified that
the bound property changed, and a method to unregister listeners. To notify
listeners, the method firePropertyChange is called with three parameters,
a string defining the name of the bound property, the bound property old
value and new value.
Reflection and Introspection - Reflection allows the discovery of a bean's contents, for example the names of public functions, properties, etc. Introspection is the process which queries a bean to discover a bean's contents using reflection. The CounterBeanInfo provides methods and data (e.g. an icon to represent the Counter) for improved introspection of a bean.
BeanInfo - A special object that assists in describing a bean properties, icon, public methods, etc. simplifying introspection. A subclass SimpleBeanInfo is generally extended through inheritance rather than implementing the more detailed BeanInfo. The key difference is that BeanInfo requires a significant number of methods to be defined that are implemented to return null in SimpleBeanInfo. Both can also be used to limit the list of public methods and properties one has access to, useful for excluding inherited methods, etc. from event handling. CounterBeanInfo is a SimpleBeanInfo object that controls which methods and properties of the Counter bean are published and defines the icon that represents the Counter bean.
Counter - Implements a bound property count, which when changed notifies other listener beans of the new count value. Key parts are:
| import java.awt.*; import java.beans.*; public class Counter extends Panel { public Counter() {
public void increment() {
} |
Monitor - Listens for property changes. Can be registered with and listen for a change in Counter or property of another bean type. When the count property of a connected Counter bean is changed, the propertyChange() method of the Monitor bean is invoked, updating the n property (i.e. the text on the label) of the Monitor bean. Note that by implementing PropertyChangeListener, Monitor must define propertyChange() method.
| import java.awt.*; import java.beans.*; public class Monitor extends Panel implements PropertyChangeListener { private TextField n = new TextField(4); public Monitor() { add(n); n.setText(" "); setBackground(Color.orange); }
} |
BeanCounter - Here we add two listeners, monitor1 and monitor2, each notified of the Counter property change. Key part is registration as a listener of changes to the Counter property, counter1.addCounterListener( monitor1 ). When Counter calls firePropertyChange() method, all listeners are notified.
BeanCounter.java import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class BeanCounter extends Applet {
private Counter counter1;
private Button button1;
private Monitor monitor1, monitor2;
public void init() {
button1 = new Button("button1");
counter1 = new Counter();
monitor1 = new Monitor();
monitor2 = new Monitor() ;
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
counter1.increment();
}
});
counter1.addCounterListener( monitor1 );
counter1.addCounterListener( monitor2 );setLayout(new FlowLayout());
add(button1);
add(counter1);
add(monitor1);
add(monitor2);
}
}
<APPLET code="BeanCounter.class" width=100 height=100> </APPLET>
Why use properties? The advantage can be seen in BeanCounter.java which connects a Counter and Monitor object in counter1.addCounterListener( monitor1 ). How and what is passed between the two objects is handled by the objects themselves; the BeanCounter is not involved in the execution of a change in the Counter or notification of the Monitor.
Essentials
Counter with Bound Property
import java.beans.*; public class Counter extends Panel {
private PropertyChangeSupport pcsupport = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener l) {
pcsupport.addPropertyChangeListener(l);
}public void increment() {
pcsupport.firePropertyChange
("count", new Integer(oldcount), new Integer(count));}
}
Monitor
import java.beans.*;
public class Monitor extends Panel implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent e) {
n.setText( (Integer)e.getNewValue() + "");
}}
BeanCounter.java public class BeanCounter extends Applet {
private Counter counter1;
private Monitor monitor1;
public void init() {
counter1 = new Counter();
monitor1 = new Monitor();
counter1.addCounterListener( monitor1 ); }
}
CounterBeanInfo - Provides additional control of reflection for a Counter bean properties and methods. The icon representation is reflected through the getIcon method. Information that the count property is bound and that the Display Name of the count property is the Counter is defined though the PropertyDescriptor object. The publication of Counter methods is restricted to increment through the MethodDescriptor object.
| import java.awt.*; import java.beans.*; import java.lang.reflect.*; public class CounterBeanInfo extends SimpleBeanInfo { |
| Name: countProperty/Counter.class Java-Bean: True Name: countProperty/Monitor.class Java-Bean: True Name: countProperty/CounterBeanInfo.class Java-Bean: False Name: countProperty/Counter.gif Java-Bean: False |
Click to download Counter.gif |
Serialization is a means of creating persistent objects, those that can be transmitted for locally storing or transfer across a network. Serialization refers to the output of an object in a representation that can be input in its original state; important for saving the state of an object but also for transmitting an object state over a network in a distributed environment.
Serialization requires reading and writing objects and is implemented by methods readObject and writeObject. Any object that inherits or implements Serializable can be read or written although, in some cases, the programmer may need to implement appropriate methods. The following example serializes and writes to a file the state of a simple SketchApp object. Since SketchApp inherits from Frame it inherits serialization and a show() method to display the frame. The SketchRead reads a serialized SketchApp object and displays all properties at the point the SketchApp was serialized.
Writing - SketchApp object is written by the Sketch class. The key to writing a serialized SketchApp object is output.writeObject(sketchapp); which writes all serializable properties to the file "Sketch.ser". Note that the Vector points is one of the properties written.
Reading - SketchApp object is read by the SketchRead class. The key to reading a serialized SketchApp object is (SketchApp) input.readObject();. The input.readObject( ) reads the object input file "Sketch.ser", (SketchApp) casts the object read into a SketchApp object. The Vector points is input with the values at the time the SketchApp object was serialized.
| import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; class SketchApp extends Frame { public SketchApp () { |
public class Sketch { public static void main(String arg[]) { Button serialize = new Button("Serialize"); final SketchApp sketchapp = new SketchApp(); sketchapp.add(serialize, BorderLayout.SOUTH ); sketchapp.show();
}
|
| import java.awt.*; import java.awt.event.*; import java.io.*; public class SketchRead {
input.close();
|
What was serialized by Sketch and restored by SketchRead.
|
Use - cannot be executed as an applet because must access file system to save the serialized sketch.
RMI (Remote Method Invocation) supports distributed processing by providing for an object on one machine to invoke a method on another and receive the results. The Java text does not discuss RMI. The machines could be the same or connected over a network. The server object provides resources through a set of methods that can be called remotely from the client. In some ways, RMI is similar to network programming via sockets. The primary advantage of RMI is that it is simple. Objects can be passed between two machines as a single entity rather than implementing a protocol to transfer the object over a connection. One key disadvantage is that it is only useable between RMI clients and servers, restricting it to Java. The key elements of an RMI system are:
It is important to note that method arguments and returned results are arbitrarily complex objects. To transport an object over a network it must be serialized into a form that could be written to a file and read later or transmitted and reconstructed on the receiving end. Both the client and the server methods have full access to the same object.
The following implements a "Hello World" server. A client invokes the sayHello() method on the server which returns the string "Hello World". In this case the client and server are both on the same machine but, by adding a network name, remote servers could be contacted. In this example, security is a function of object definition. If a server method or attribute is public a client has access, reasonable considering that is the same external access were the object part of a single program.
The following list and diagram shows the communication between an RMI client and server. The steps to executing the RMI program below are:
| // Interface file on both client and server machines -
Hello.java import java.rmi.Remote; import java.rmi.RemoteException; public interface Hello extends Remote { |
||
| // Client program - HelloClient.java import java.rmi.Naming; import java.rmi.RemoteException; public class HelloClient {
} |
||
| // Server program - HelloServer.java import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.RMISecurityManager; import java.rmi.server.UnicastRemoteObject; public class HelloServer extends UnicastRemoteObject implements Hello { public HelloServer() throws RemoteException {
public static void main(String args[]) throws Exception { if (System.getSecurityManager()
== null) { // Create and install a security manager
System.out.println("HelloWorldServer bound in registry"); |
Use - The steps required for compiling and registering the server on 2000/XP are:
Document last modified: