next up previous contents
Next: BeanBoxの動的なイベント処理 Up: Bound Property と Previous: Constrained Property

PropertyVetoExceptionとVoterサンプル

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

最後に、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));
    }
    ......
    ......
}
=========================================================================


maruyama@wakhok.ac.jp