Bean Introspection  «Prev 

Multicast event Design Patterns

Events and Event Listeners

Events[1] are important because they allow a Bean to inform an interested party of internal state changes.
Events come in a variety of different forms, but some common ones are mouse clicks and drags.
For example, when the user drags the mouse over a Bean, the Bean broadcasts an event notification to the event listeners[2] that have registered themselves with that Bean.

Serializing Event Listeners

Event-source objects keep references to their target event listeners, either directly or indirectly through a support object. It is very important to recognize that these listeners may not be serializable. For instance, if you keep a Vector of event listeners, an attempt will be made to serialize the listeners when the Vector is serialized. One possible solution is to mark the collection of event listeners as transient. But we certainly do not want to ignore the listeners, as some or all of them may very well be serializable. The best we can do is to serialize those listeners that can be serialized, and skip the others. Let us look at a simple example class called SimpleTemperature that fires a TemperatureChangeEvent to its registered listeners. References to those listeners are kept in a Vector called listeners. Since we don't know if the elements of listeners are serializable, we mark listeners as transient. We won't actually be serializing listeners at all, only those elements of it that are serializable. We really don't even need to construct the Vector until an event listener is added, so we won't create it until it's needed. The code illustrating this is next.

Developing Java Beans
public class SimpleTemperature
{
 // collection of temperature change listeners
 protected transient Vector listeners = null;
 public synchronized void
  addTemperatureChangeListener(TemperatureChangeListener l){
   // if the vector doesn't exist yet, create it now
   if (listeners == null){
    listeners = new Vector();
   }
   // add the listener
   if (!listeners.contains(l)){
    listeners.addElement(l);
   }
  }
  public synchronized void
   removeTemperatureChangeListener(TemperatureChangeListener l)
   {
    // if we have a collection of listeners, attempt to remove
    // the specified listener
    if(listeners != null){
     listeners.removeElement(l);
    }
  }
  private void writeObject(ObjectOutputStream stream)
   throws java.io.IOException
  {
   // perform default writing first
   stream.defaultWriteObject();
   // clone the vector in case one is added or removed
   Vector v = null;
   synchronized (this){
    if (listeners != null){
     v = (Vector)listeners.clone();
    }
   }
   // if we have a collection...
   if (v != null){
    int cnt = v.size();
    for(int i = 0; i < cnt; i++){
     // get the listener element from the collection
     TemperatureChangeListener l =
     (TemperatureChangeListener)v.elementAt(i);
     // if the listener is serializable, write it to the stream
     if (l instanceof Serializable){
      stream.writeObject(l);
     }
    }
   }
   // a null object marks the end of the listeners
   stream.writeObject(null);
  }
  // handle the reading of the object state
  private void readObject(ObjectInputStream stream)
   throws java.io.IOException
  {
   try{
    stream.defaultReadObject();
    Object l;
    while(null != (l = stream.readObject())){
     addTemperatureChangeListener((TemperatureChangeListener)l);
    }
   }
   catch (ClassNotFoundException e){
    throw new IOException();
   }
  }
 }
We have an addTemperatureChangeListener() method for registering event listeners. This is where we create the listeners Vector if we don't have one yet. There is also the corresponding removeTemperatureChangeListener() method, where we must first check for the existence of the Vector before we attempt to remove the listener element. Since we marked listeners as transient, we need to implement our own readObject() and writeObject() methods to serialize the event listeners.

[1]Event: something that happens within a Bean (or component) that an application or other component might want to know about and possibly react to.
[2]Event listener: a Bean or application capable of responding to events.