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)); } ...... ...... } =========================================================================