El API de JavaBeans proporciona un mecanismo de eventos similar al mecanismo de las propiedades compartidas, que permite a los objetos vetar los cambios de una propiedad de un Bean.
Existen tres partes en la implementación de una propiedad Restringida:
La clase VetoableChangeSupport se proporciona para implementar estas capacidades. Esta clase implementa métodos para añadir y eliminar objetos VetoableChangeListener a una lista de oyentes, y un método que dispara eventos de cambio de propiedad a todos los oyentes de la lista cuando se propone un cambio de propiedad. Este método también capturará cualquier veto, y re-enviará el evento de cambio de propiedad con el valor original de la propiedad. Nuestro Bean puede descencer de la clase VetoableChangeSupport, o utilizar un ejemplar de ella.
Observa que, en general, las propiedades restringidas también deberían ser propiedades compartidas. Cuando ocurre un cambio en una propiedad restringida, puede ser enviado un PropertyChangeEvent mediante PropertyChangeListener.propertyChange() para indicar a todos los Beans VetoableChangeListener que el cambio a tenido efecto.
El Bean JellyBean tiene una propiedad restringida. Veremos su código para ilustrar los pasos e implementar propiedades restringidas:
private VetoableChangeSupport vetos =
new VetoableChangeSupport(this);
VetoableChangeSupport maneja una lista de objetos VetoableChangeListener, y dispara eventos de cambio de propiedad a cada objeto de la lista cuando ocurre un cambio en una propiedad restringida.
public void addVetoableChangeListener(VetoableChangeListener l) {
vetos.addVetoableChangeListener(l);
}
public void removeVetoableChangeListener(VetoableChangeListener l) {
vetos.removeVetoableChangeListener(l);
}
public void setPriceInCents(int newPriceInCents)
throws PropertyVetoException {
int oldPriceInCents = ourPriceInCents;
// First tell the vetoers about the change. If anyone objects, we
// don't catch the exception but just let if pass on to our caller.
vetos.fireVetoableChange("priceInCents",
new Integer(oldPriceInCents),
new Integer(newPriceInCents));
// No-one vetoed, so go ahead and make the change.
ourPriceInCents = newPriceInCents;
changes.firePropertyChange("priceInCents",
new Integer(oldPriceInCents),
new Integer(newPriceInCents));
}
Observa que setPriceInCents() almacena el valor antiguo de price, porque los dos valores, el nuevo y el antiguo, deben ser pasados a fireVetoableChange(). También observa que los precios primitivos int se han convertido a objetos Integer.
public void fireVetoableChange(String propertyName,
Object oldValue,
Object newValue)
throws PropertyVetoException
Estos valores se han empaquetado en un objeto PropertyChangeEvent enviado a cada oyente. Los valores nuevo y antiguo son tratados como valores Object, por eso si son tipos primitivos como int, deben utilizarse sus versiones objetos como java.lang.Integer.
Ahora necesitamos implementar un Bean que escuche los cambios en las propiedades restringidas.
void vetoableChange(PropertyChangeEvent evt)
throws PropertyVetoException;
Por eso para hacer que nuestra clase pueda escuchar y responder a los eventos de cambio de propiedad debe:
Observa que el objeto VetoableChangeListener frecuentemente es una clase adaptador. La clase adaptador implementa el interface VetoableChangeListener y el método vetoableChange(). Este adaptador es añadido a la lista de oyentes del Bean restringido, intercepta la llamada a vetoableChange(), y llama al método del Bean fuente que ejerce el poder del veto.
El BeanBox genera una clase adaptador cuando se conecta un Bean que tiene una propiedad restringida con otro Bean. Para ver como funciona esto, sigue estos pasos:
Detrás de la escena el BeanBox genera el adaptador de evento. Este adaptador implementa el interface,
VetoableChangeListener, y también genera un método vetoableChange() que llama al método Voter.vetoableChange(). Aquí tienes el código generado para el adaptador:
// Automatically generated event hookup file.
package tmp.sunw.beanbox;
import sunw.demo.misc.Voter;
import java.beans.VetoableChangeListener;
import java.beans.PropertyChangeEvent;
public class ___Hookup_1475dd3cb5 implements
java.beans.VetoableChangeListener, java.io.Serializable {
public void setTarget(sunw.demo.misc.Voter t) {
target = t;
}
public void vetoableChange(java.beans.PropertyChangeEvent arg0)
throws java.beans.PropertyVeto Exception {
target.vetoableChange(arg0);
}
private sunw.demo.misc.Voter target;
}
El Bean Voter no necesita implementar el interface VetoableChangeListener; en su lugar, la clase adaptador generada implementa VetoableChangeListener. El método vetoableChange() del adaptador llama al método apropiado en el objeto fuente (Voter).
void addVetoableChangeListener(String propertyName,
VetoableChangeListener listener);
void removeVetoableChangeListener(String propertyName,
VetoableChangeListener listener);
Como alternativa, por cada propiedad restingida de un Bean se pueden proporcionar métodos con la siguiente firma para registrar y eliminar oyentes de una propiedad básica:
void add<PropertyName>Listener(VetoableChangeListener p); void remove<PropertyName>Listener(VetoableChangeListener p);