VetoableChangeSupportは、PropertyChangeEventを送り出す側の手助けをする のですが、このイベントを受けて、場合によったら PropertyVetoException をなげ返す側は、どのような準備が必要でしょうか? それは、Vetoableな、 PropertyChangeEventを受け取るのですから、VetoableChangeListener インタフェースを実装したクラスでなければなりません。
まず、このクラスが、生成するPropertyVetoExceptionの構造を、見ておきましょう。 このExceptionは、どのPropertyChangeEventが、PropertyVetoExceptionを引き起こ したかが分かるように、イベント情報をうちに含んでいます。
==========================================================================
public
class PropertyVetoException extends Exception {
public PropertyVetoException(String mess, PropertyChangeEvent evt) {
super(mess);
this.evt = evt;
}
public PropertyChangeEvent getPropertyChangeEvent() {
return evt;
}
private PropertyChangeEvent evt;
}
=========================================================================
つぎのリストを見てください。 ここでは、VetoableChangeListenerを実装した、VetoableChangeAdaptorクラスが 定義されて、それがjellyBeanの発するPropertyChangeEventのリスナーとして 登録されています。VetoableChangeListenerでもっとも大事な働きをするのは、 vetoableChangeメソッドですが、このサンプルでのこのメソッドの定義を見て ください。Voterクラスの、同名のvetoableChangeメソッドを呼び出しています。 このvetoableChangeメソッドは、もはや、VetoableChangeListenerで実装を求め られているものではないことに注意して下さい。
=========================================================================
import sunw.demo.jelly.JellyBean;
import sunw.demo.misc.Voter;
import java.beans.*;
public class DemoVoter
{
JellyBean bean = new JellyBean();
Voter voter = new Voter();
VetoableChangeAdapter adapter = new VetoableChangeAdapter();
DemoVoter()
{
// voter.setVetoAll(false);
bean.addVetoableChangeListener(adapter);
try {
bean.setPriceInCents(123);
}
catch (PropertyVetoException e) {
System.err.println("Vetoed: " + e);
}
}
class VetoableChangeAdapter implements VetoableChangeListener
{
public void vetoableChange(PropertyChangeEvent e)
throws PropertyVetoException
{
voter.vetoableChange(e);
}
}
public static void main(String[] argv)
{
new DemoVoter();
}
}
=========================================================================
このサンプルは、JellyBeansのsetPriceInCents(123)メソッドが発するイベント が、Voterクラスのオブジェクト上でのvetoableChangeメソッドの呼び出しが、 PropertyVetoExceptionを返さなければ、そのまま終了し、もしも、Exceptionが 返れば、"Vetoed: "というメッセージを返すという単純なものです。 次のリストを見れば分かるように、 Voterクラスのオブジェクト上のvetoableChangeメソッドは、内部変数 vetoAllの 値がtrueならPropertyVetoExceptionを返し、falseなら、何もしません。 結局、JellyBeansのsetPriceInCentsメソッドが、効果を持つか否かは、 Voterオブジェクトの状態によることになります。もちろん、この状態は、 setVetoAllメソッドで変更することが出来ます。
=========================================================================
public class Voter extends Component {
private boolean vetoAll = true;
private String text = "No";
private transient int baseline;
public void setVetoAll(boolean x) {
vetoAll = x;
if (vetoAll) {
text = "No";
} else {
text = "Yes";
}
repaint();
}
public void vetoableChange(PropertyChangeEvent x)
throws PropertyVetoException {
if (vetoAll) {
throw new PropertyVetoException("NO!", x);
}
}
......
......
}
=============================================================================
最後に、JellyBeanクラスのsetPriceInCentsメソッドを、もう少し詳しく見て みましょう。次のリストを見てください。 このメソッドは、前半のVetoableChangeSupportクラスのインスタンス上での fireVetoableChangeメソッドの呼び出しと、後半の、PropertyChangeSupportクラス のインスタンス上でのfirePropertyChangeメソッドの呼び出しから構成されています。
先に見たようにfireVetoableChangeメソッドは、本質的には、リスナー・オブジェクト 上でのVetoableChangeメソッドの呼び出しですので、Voterが"Yes"状態の時には、 この前半部分は、何もしないということになり、そのまま、後半部分の、 firePropertyChangeによる、プロパティの変更へと進んで行きます。
逆に、Voterが"No"状態の場合には、fireVetoableChangeメソッドの呼び出しは、 PropertyVetoException を引き起こします。大事なことは、この時点で、 setPriceInCentsメソッド自身がPropertyVetoExceptionを返しますので、この時 には、setPriceInCentsの後半部分は、全く実行されないことになります。
=========================================================================
public class JellyBean extends java.awt.Component {
private PropertyChangeSupport changes = new PropertyChangeSupport(this);
private VetoableChangeSupport vetos = new VetoableChangeSupport(this);
private Color ourColor = Color.orange;
private int ourPriceInCents = 2;
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));
}
......
......
}
=========================================================================