next up previous contents
Next: PropertyVetoExceptionとVoterサンプル Up: Bound Property と Previous: BeanBoxでのProperty Bind

Constrained Property

JavaBeansのプロパティには、今まで見てきた Bound Propertyと並んで、もう一つ 大事なプロパティの種類があります。それが、Constrained Propertyです。 「拘束条件付きプロパティ」とでも訳せばいいのでしょうか。同じ概念が、 vetoable Property 「拒否権付きプロパティ」とも呼ばれる時もあります。 こちらの方が分かりやすいかもしれません。

Bound Propertyも Constrained Propertyも、Propertyが変更されたとき、同じく PropertyChangeEventをリスナーに送り出します。ここは、共通です。 Bound Propertyと Constrained Propertyは、発生するプロパティによって 区別されるわけではありません。両者は、PropertyChangeListnerをリスナーに 持つか、あるいは、VetoableChangeListenerをリスナーに持つかによって区別され ます。また、リスナー・オブジェクトで呼び出されるのは、前者では propertyChange メソッドであり、後者では vetoableChangeメソッドです。

Java Beansのイベント・モデルの命名規則が、少しですが、破綻していることに 注意してください。これは、VetoableChangeEvent(こうした名前のクラスは存在しま せん!)が、通常のPropertyChangeEventの、きわめて近いバリエーションであることを 考えれば了解できることだと思います。

VetoableChangeSupport

Constrained Propertyをもつインスタンスは、PropertyChangeイベントの送り出し 中に、リスナーから、PropertyVetoException を一つでも受け取れば、プロパティの 変更に「拒否権」が発動されたと考えて、それ以上のイベントの送り出しを止める ばかりか、それまで行われたリスナーに対する変更を、取り消ししようとします。 こうした働きは、VetoableChangeSupportクラスによって担われています。 次のリストを見てください。

=============================================================================
public class VetoableChangeSupport implements java.io.Serializable {

    transient private java.util.Vector listeners;
    private Object source;
    private int vetoableChangeSupportSerializedDataVersion = 1;

    public void fireVetoableChange(String propertyName, 
                                        Object oldValue, Object newValue)
                                        throws PropertyVetoException {

        if (oldValue != null && oldValue.equals(newValue)) {
            return;
        }

        java.util.Vector targets;
        synchronized (this) {
            if (listeners == null) {
                    return;
            }
            targets = (java.util.Vector) listeners.clone();
        }
        PropertyChangeEvent evt = new PropertyChangeEvent(source,
                                            propertyName, oldValue, newValue);

        try {
            for (int i = 0; i < targets.size(); i++) {
                VetoableChangeListener target = 
                                (VetoableChangeListener)targets.elementAt(i);
                target.vetoableChange(evt);
            }
        } catch (PropertyVetoException veto) {
            // Create an event to revert everyone to the old value.
                   evt = new PropertyChangeEvent(source, propertyName, newValue, oldValue);
            for (int i = 0; i < targets.size(); i++) {
                try {
                    VetoableChangeListener target =
                                (VetoableChangeListener)targets.elementAt(i);
                    target.vetoableChange(evt);
                } catch (PropertyVetoException ex) {
                     // We just ignore exceptions that occur during reversions.
                }
            }
            // And now rethrow the PropertyVetoException.
            throw veto;
        }
    }

}

=============================================================================

次の部分が、VetoableChangeListenerへの、イベントの送り出しの部分です。 これは、通常のイベントの送り出しで見られる、よくあるパターンです。 問題は、実は、このすぐ後ろに続く、PropertyVetoException が返ってきた時の 「例外処理」部分です。先のリストのこの部分を、もう一度、よく見て下さい。

        try {
            for (int i = 0; i < targets.size(); i++) {
                VetoableChangeListener target = 
                                (VetoableChangeListener)targets.elementAt(i);
                target.vetoableChange(evt);
            }

イベントの送り直し

最初の送りだしでは、

   evt = new PropertyChangeEvent(source, propertyName, oldValue, newValue);
という形で準備されたPropertyChangeEventが、このcatch句の中の処理では、
   evt = new PropertyChangeEvent(source, propertyName, newValue, oldValue);
という形で、改めて新しいPropertyChangeEventが作られていることに注目してくだ さい。

最初は、oldValueをnewValueに変えようとして、いくつかのオブジェクトでは成功した かも知れないが、あるオブジェクトに「拒否」されたら、それまで変更に成功した オブジェクトに対しても、この変更を、全て、取り消そうというわけです。 具体的には、全てのオブジェクトに、newValueをoldValueに変更するような PropertyChangeEventを、もう一度、送り付けることになります。この時にも、 Exceptionが発生する可能性はあるのですが、それは、無視しています。

それはそれで、一つのシナリオとしては分かるのですが、「拒否」をどのように 処理するかについては、このほかにもいろいろな想定が可能だと思います。 このsupportクラスは、多少、強い想定をしていると感じています。



maruyama@wakhok.ac.jp