A bean responds to events using public methods.
However, these do not include the
setters and getters
(e.g. in the BeanBox builder tool. )
The SimpleBean2 has no public methods other than its setters and getters. Therfore it has nothing with which to respond to an event generated by another bean.
You can show this.
The pop up menu shows available methods which can be called in response to the ActionEvent from your button.
Note that the setters and getters are not listed. The methods listed are all inherited by the SimpleBean from its ancestor classes. None of these inherited methods do anything useful for the SimpleBean.
Suppose now that you want to add a button that will generate events for SimpleBean2.
The simplest way to make a bean responsive to incoming events from a button is
to create some no argument public methods for the bean.
For example, we add a simple method in SimpleBean2 to get SimpleBean3. The latter has a new public method, dumb() which sets its msg field to "dumb".
For the BeanBox such methods must not have arguments. If dumb() has an argument, such as dumb(String s), the BeanBox won't recognize it. See SimpleBean4.
You will notice that after the receiving method has been chosen (e.g dumb() in SimpleBean3) the BeanBox generates an adapter class which makes the connection.
Here is such a generated adapter class.
// Automatically generated an adapter file that handles ActionEvent. package tmp.sunw.beanbox; import SimpleBean3; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; public class ___Hookup_162ba10135 implements java.awt.event.ActionListener, java.io.Serializable { public void setTarget(SimpleBean3 t) { target = t; } public void actionPerformed(java.awt.event.ActionEvent arg0) { target.dumb(); } private SimpleBean3 target; }
This adapter class implements the ActionListener interface by implementing the one method belonging to that interface, actionPerformed(ActionEvent).
The BeanBox calls setTarget(targetBean) to get a referece to the target bean (in this case SimpleBean3), and uses this reference to call the no argument public method dumb().
You can also write your own adapters (see the discussion in Chapter 3 of Java Beans by Robert Englander, O'Reilly, for additional details).
Most useful beans generate their own events.
To create such events you need to add methods to your bean
to register and unregister clients for the events it generates.
Your bean needs to be able to fire its events (notify listeners) under the right circumstances.
You must also create corresponding event objects and corresponding listener interfaces that clients can implement.
You are really implementing a client server mechanism within one JVM. Your bean is a server, other beans are clients.
As an example, here is a bean which counts up from 0
until some predefined number is reached.
At this point it either restarts the count, or fires an event.
It can receive counts from another bean, and the event it fires can be received by other beans.
The counter class has maxValue field, and there are methods that set and get this value: consequently, maxValue is a property that is displayed and can be changed in the "Properties" window (when counter bean is loaded into BeanBox).To see the counter bean in action, do the following sequence:
You might want to change the interval property of the TickTock bean to 1 from 5 seconds (click on the bean and change the interval in the "Properties" window).
You can watch now the counter bean in action. However, with these settings nothing happens because the counter rollover property is set to true. So when the counter reaches 20 it just rolls over to 1 and starts again.
To get the counter to fire its event, change its boolean rollover property to false. The juggler stops when the count reaches 20.
This counter bean comes in three parts:
Consider first the event (source code: MaxValueEvent.java.)
package counter; public class MaxValueEvent extends java.util.EventObject { public MaxValueEvent(Object source) { super(source); } }
This is as simple an event as you can get.
The minimum things clients need to know is where the object came from.
Note that the name of this class must end in
"Event".
This is part of the bean design patterns.
Next we need the interface for clients (or the builder tool) to implement (source code: MaxValueListener.java)
package counter; import java.util.EventListener; public interface MaxValueListener extends EventListener { void maxValueReached(MaxValueEvent m); }
The name for the listener must end in "Listener". Note that
And here is the main body of bean code (source code: Counter.java)
/* * From John Hunt (modified) , Learn Java Beans Fast, (Springer 1999) * Counts repeatedly from minValue to maxValue if rollOver is true. * Otherwise, firers a MaxValueEvent. */ package counter; import java.awt.*; import java.util.*; import java.io.Serializable; public class Counter extends Panel implements Serializable { private long count; private long initialValue = 0, maxValue = 5; private Label label; private Vector listeners = new Vector(); private boolean rollOver; public Counter() { setBackground(Color.blue); setForeground(Color.white); setRollOver(true); label = new Label(initialValue + ""); add(label); } public void setInitialValue(long start) { initialValue = start; reset(); } public long getInitialValue() { return initialValue; } public void setMaxValue(long end) { maxValue = end; } public long getMaxValue() { return maxValue; } public boolean isRollOver() { return rollOver; } public void setRollOver(boolean state) { rollOver = state; } public Dimension getMinimumSize() { return new Dimension(30,30); } public Dimension getPreferredSize() { return new Dimension(60, 30); } public void reset() { count = initialValue; label.setText(count + ""); } /* * These add and remove methods must follow the proper design pattern * in order for introspection to take place. * add<event name>Listener(<event name>Listener <listner reference>) * remove<event name>Listener(<event name>Listener <listener reference>) */ public synchronized void addMaxValueListener(MaxValueListener hearer) { listeners.addElement(hearer); } public synchronized void removeMaxValueListener(MaxValueListener hearer) { listeners.removeElement(hearer); } /* * Fire the event when the count reaches the trigger value */ public void increment() { if(count != maxValue) { count++; label.setText("" + count); } else if (isRollOver() ) { reset(); } else { MaxValueEvent me = new MaxValueEvent(this); synchronized(this) { for(Enumeration e = listeners.elements(); e.hasMoreElements();) { MaxValueListener ml = (MaxValueListener) e.nextElement(); ml.maxValueReached(me); // fire the event to this listener } } } } }
There are a number of interesting points about this code.
Note also the synchronization to prevent the vector from becoming messed up if a call to remove comes in while the bean is firing events.
Note also the last line of code:
Remember too that the client is often an adapter class
that acts as an intermediary between the bean and its real clients.
Here are two adapter classes automatically generated when you connect
counter, juggler and TickTock:
calls stopJuggling()
in Juggler,
calls increment()
in counter.
Finally, there is also the manifest file. manifest.tmp
Name: counter.Counter.class Java-Bean: True Name: counter.MaxValListener.class Java-Bean: False Name: counter.MaxValEvent.class Java-Bean: False Name: counter.Counter.java Java-Bean: False Name: counter.MaxValueListener.java Java-Bean: False Name: counter.MaxValueEvent.java Java-Bean: False
Once the Java files are compiled you can make a jar file (from the directory above the directory, counter) using the following command:
Note what isn't there in all the examples so far.
Even though we have created an event firing bean, Counter, we have not used anything from the beans API. Everything is ordinary Java code. The only thing we have done to make the bean available to a builder tool is to follow appropriate design patterns for names.
The designers of Java Beans deliberately made them so that they are just Java Classes. Nothing special is needed to create a bean.
The Java Bean API, java.beans and java.beans.event provide extra features and convenience classes for beans. The use of these features is optional.