Author: kylem
Date: Fri Dec  3 12:36:22 2004
New Revision: 109727

URL: http://svn.apache.org/viewcvs?view=rev&rev=109727
Log:
Added support for receiving bound and constrained property PropertyChangeEvents 
as lifecycle
events on ControlBeanContext.  The onPropertyChange and onVetoableChange events 
will be delivered
when bound or constrained properties are set by an external client, and provide 
identical
semantics to registering a PropertyChangeListener or VetoableChangeListener.  
Extended the
checkin test case to verify this behavior.

Added:
   
incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/property/PropEventsTest.java
Removed:
   
incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/property/PropEvents.java
Modified:
   
incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/context/ControlBeanContext.java
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventSet.java
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm
   
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm
   
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEvents.java
   
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.jcs
   
incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/contextevent/DriveBeanRecorder.java

Modified: 
incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/context/ControlBeanContext.java
Url: 
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/context/ControlBeanContext.java?view=diff&rev=109727&p1=incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/context/ControlBeanContext.java&r1=109726&p2=incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/context/ControlBeanContext.java&r2=109727
==============================================================================
--- 
incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/context/ControlBeanContext.java
    (original)
+++ 
incubator/beehive/trunk/controls/src/api/org/apache/beehive/controls/api/context/ControlBeanContext.java
    Fri Dec  3 12:36:22 2004
@@ -18,6 +18,8 @@
  */
 
 import java.beans.beancontext.BeanContextServices;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyVetoException;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Method;
@@ -186,6 +188,23 @@
          * the associated bean has been instantiated and fully initialized.
          */
         public void onCreate();
+
+        /**
+         * The onPropertyChange event is delivered when a property setter 
method is
+         * called for a bound property on the Java Control.
+         *
+         * @see org.apache.beehive.controls.api.packaging.PropertyInfo
+         */
+        public void onPropertyChange(PropertyChangeEvent pce);
+
+        /**
+         * The onVetoableChange event is delivered when a property setter 
method is
+         * called for a constrained property on the Java Control.  A 
PropertyVetoException
+         * may be thrown to veto the change made by the client.
+         *
+         * @see org.apache.beehive.controls.api.packaging.PropertyInfo
+         */
+        public void onVetoableChange(PropertyChangeEvent pce) throws 
PropertyVetoException;
     }
 
     /**

Modified: 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java
Url: 
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java?view=diff&rev=109727&p1=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java&r1=109726&p2=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java&r2=109727
==============================================================================
--- 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java
       (original)
+++ 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java
       Fri Dec  3 12:36:22 2004
@@ -54,9 +54,12 @@
  *  - it acts as the BeanContextServicesRevokedListener when an associated 
control
  *    bean has lost access to services.
  */
-public class ControlBeanContext extends BeanContextServicesSupport
-                                        implements 
BeanContextServiceRevokedListener,
-                                                   
org.apache.beehive.controls.api.context.ControlBeanContext
+public class ControlBeanContext 
+             extends BeanContextServicesSupport
+             implements BeanContextServiceRevokedListener,
+                        
org.apache.beehive.controls.api.context.ControlBeanContext,
+                        java.beans.PropertyChangeListener,
+                        java.beans.VetoableChangeListener
 {
     /**
      * Creates a new ControlBeanContext instance associated with a specific
@@ -705,20 +708,62 @@
     //
     // ControlBeanContext.addLifeCycleListener
     //
-    public void addLifeCycleListener(LifeCycle listener)
+    synchronized public void addLifeCycleListener(LifeCycle listener)
     {
         if (_lifeCycleListeners == null)
+        {
             _lifeCycleListeners = new Vector<LifeCycle>();
+
+            //
+            // Since bound/constrained property changes are exposed as 
lifecycle events, we
+            // need to register ourselves as a listener for these events the 
first time a
+            // lifecycle listener is added.
+            //
+            _bean.getPropertyChangeSupport().addPropertyChangeListener(this);
+            _bean.getVetoableChangeSupport().addVetoableChangeListener(this);
+        }
         _lifeCycleListeners.addElement(listener);
     }
 
     //
     // ControlBeanContext.removeLifeCycleListener
     //
-    public void removeLifeCycleListener(LifeCycle listener)
+    synchronized public void removeLifeCycleListener(LifeCycle listener)
     {
         if (_lifeCycleListeners != null)
             _lifeCycleListeners.removeElement(listener);
+    }
+
+    //
+    // PropertyChangeListener.propertyChange
+    //
+    public void propertyChange(PropertyChangeEvent pce)
+    {
+        if (_lifeCycleListeners != null)
+        {
+            Iterator iter = _lifeCycleListeners.iterator();      
+            while (iter.hasNext())
+            {
+                LifeCycle listener = (LifeCycle)iter.next();
+                listener.onPropertyChange(pce);
+            }
+        }
+    }
+
+    //
+    // VetoableChangeListener.vetoableChange
+    //
+    public void vetoableChange(PropertyChangeEvent pce) throws 
PropertyVetoException
+    {
+        if (_lifeCycleListeners != null)
+        {
+            Iterator iter = _lifeCycleListeners.iterator();      
+            while (iter.hasNext())
+            {
+                LifeCycle listener = (LifeCycle)iter.next();
+                listener.onVetoableChange(pce);
+            }
+        }
     }
 
     /**

Modified: 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventSet.java
Url: 
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventSet.java?view=diff&rev=109727&p1=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventSet.java&r1=109726&p2=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventSet.java&r2=109727
==============================================================================
--- 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventSet.java
 (original)
+++ 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventSet.java
 Fri Dec  3 12:36:22 2004
@@ -17,12 +17,13 @@
  * $Header:$
  */
 
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
+
 import com.sun.mirror.apt.AnnotationProcessorEnvironment;
 import com.sun.mirror.declaration.InterfaceDeclaration;
 import com.sun.mirror.declaration.MethodDeclaration;
+import com.sun.mirror.type.InterfaceType;
 
 import org.apache.beehive.controls.api.packaging.EventSetInfo;
 import org.apache.beehive.controls.api.packaging.FeatureInfo;
@@ -49,6 +50,10 @@
         _eventSet = eventSet;
         _env = env;
 
+        //
+        // TODO: Identify any super interface for this event set
+        //
+
         _events = initEvents();
     }
 
@@ -62,10 +67,33 @@
             return events;
 
         //
-        // Add all event methods to the event list
+        // Add all of the public methods directly declared and inherited from 
extended
+        // interfaces, except for the EventSet super interface (if any)
         //
-        for (MethodDeclaration methodDecl : _eventSet.getMethods())
-            events.add(new AptEvent(this, methodDecl, _env));
+        ArrayList<InterfaceDeclaration> intfList = new 
ArrayList<InterfaceDeclaration>();
+        intfList.add(_eventSet);
+        for (int i = 0; i < intfList.size(); i++)
+        {
+            InterfaceDeclaration intfDecl = intfList.get(i);
+
+            // TODO: Ignore the superinterface (if any) and continue here
+
+            //
+            // Add all declared methods on the current interface
+            //
+            for (MethodDeclaration methodDecl : intfDecl.getMethods())
+                events.add(new AptEvent(this, methodDecl, _env));
+
+            //
+            // Add all superinterfaces of the target interface to the list
+            //
+            for (InterfaceType superType: intfDecl.getSuperinterfaces())
+            {
+                InterfaceDeclaration superDecl = superType.getDeclaration();
+                if (superDecl != null && !intfList.contains(superDecl))
+                    intfList.add(superDecl);
+            }
+        }
 
         return events;
     }

Modified: 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm
Url: 
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm?view=diff&rev=109727&p1=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm&r1=109726&p2=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm&r2=109727
==============================================================================
--- 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm
   (original)
+++ 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm
   Fri Dec  3 12:36:22 2004
@@ -178,8 +178,10 @@
         throws java.beans.PropertyVetoException
         #end
     {
-
         #if ($property.bound || $property.constrained)
+        // Ensure the control impl exists, since it may want to receive 
property events
+        ensureControl();
+
         Object oldValue = getRawControlProperty($property.keyName);
         #end
 

Modified: 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm
Url: 
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm?view=diff&rev=109727&p1=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm&r1=109726&p2=incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm&r2=109727
==============================================================================
--- 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm
       (original)
+++ 
incubator/beehive/trunk/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm
       Fri Dec  3 12:36:22 2004
@@ -66,7 +66,7 @@
 
 public class ${bean.shortName}BeanInfo extends java.beans.SimpleBeanInfo
 {
-    #if ($intf.operations.size() != 0)
+    #if ($intf.operations.size() != 0 || $intf.eventSets.size() != 0)
     #declareMethodStatics()
 
     static

Modified: 
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEvents.java
Url: 
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEvents.java?view=diff&rev=109727&p1=incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEvents.java&r1=109726&p2=incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEvents.java&r2=109727
==============================================================================
--- 
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEvents.java
       (original)
+++ 
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEvents.java
       Fri Dec  3 12:36:22 2004
@@ -61,11 +61,15 @@
 
     //
     // These EventSets are used as an external test point for events received 
by the
-    // implementation class
+    // implementation class.  The implementation will simply echo the 
ControlBeanContext
+    // lifecycle events it receives as events on these event sets.  This 
enables events
+    // received by the Impl to be matched against those received by an 
externally registered
+    // listener.  Except in veto scenarios, where someone later on the veto 
chain may not
+    // receive an event, they should be equivalent.
     //
-    //@EventSet
-    //public interface PropertyChangeOnImpl extends PropertyChangeListener {}
+    @EventSet
+    public interface ImplPropertyChange extends PropertyChangeListener {}
 
-    //@EventSet
-    //public interface VetoableChangeOnImpl extends VetoableChangeListener {}
+    @EventSet
+    public interface ImplVetoableChange extends VetoableChangeListener {}
 }

Modified: 
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.jcs
Url: 
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.jcs?view=diff&rev=109727&p1=incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.jcs&r1=109726&p2=incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.jcs&r2=109727
==============================================================================
--- 
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.jcs
    (original)
+++ 
incubator/beehive/trunk/controls/test/src/controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.jcs
    Fri Dec  3 12:36:22 2004
@@ -1,16 +1,42 @@
 package org.apache.beehive.controls.test.controls.property;
 
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyVetoException;
+
 import org.apache.beehive.controls.api.bean.ControlImplementation;
 import org.apache.beehive.controls.api.context.Context;
 import org.apache.beehive.controls.api.context.ControlBeanContext;
+import org.apache.beehive.controls.api.events.Client;
+import org.apache.beehive.controls.api.events.EventHandler;
 
 @ControlImplementation
 public class PropEventsImpl implements PropEvents
 { 
     static final long serialVersionUID = 1L;
 
-    @Context
-    ControlBeanContext context;
+    @Context ControlBeanContext context;
+
+    @Client ImplPropertyChange changeNotifier;
+
+    @Client ImplVetoableChange vetoNotifier;
+
+    //
+    // Receive context propertyChange events and echo them as external 
callbacks
+    //
+    @EventHandler(field="context", 
eventSet=ControlBeanContext.LifeCycle.class, 
+                  eventName="onPropertyChange")
+    public void onPropertyChange(PropertyChangeEvent pce)
+    {
+        changeNotifier.propertyChange(pce);
+    }
 
-    // Does nothing (for now)
+    //
+    // Receive context vetoableChange events and echo them as external 
callbacks
+    //
+    @EventHandler(field="context", 
eventSet=ControlBeanContext.LifeCycle.class, 
+                  eventName="onVetoableChange")
+    public void onVetoableChange(PropertyChangeEvent pce) throws 
PropertyVetoException
+    {
+        vetoNotifier.vetoableChange(pce); 
+    }
 }

Modified: 
incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/contextevent/DriveBeanRecorder.java
Url: 
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/contextevent/DriveBeanRecorder.java?view=diff&rev=109727&p1=incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/contextevent/DriveBeanRecorder.java&r1=109726&p2=incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/contextevent/DriveBeanRecorder.java&r2=109727
==============================================================================
--- 
incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/contextevent/DriveBeanRecorder.java
       (original)
+++ 
incubator/beehive/trunk/controls/test/src/drivers/org/apache/beehive/controls/test/driver/contextevent/DriveBeanRecorder.java
       Fri Dec  3 12:36:22 2004
@@ -1,5 +1,6 @@
 package org.apache.beehive.controls.test.driver.contextevent;
 
+import java.beans.PropertyChangeEvent;
 import java.lang.Class;
 import org.apache.beehive.controls.api.context.ControlBeanContext;
 import org.apache.beehive.controls.api.context.ResourceContext;
@@ -43,10 +44,13 @@
 
                        ControlBeanContext beanContext = 
myControl.getControlBeanContext();
                        beanContext.addLifeCycleListener( new 
ControlBeanContext.LifeCycle()
-                               {
-                                       public void onCreate() {
-                                               onCreateReceived=true; };
-                                       });
+                                   {
+                                           public void onCreate() { 
onCreateReceived=true; };
+                        public void onPropertyChange(PropertyChangeEvent pce) 
{};
+                        public void onVetoableChange(PropertyChangeEvent pce) 
{};
+                                       }
+
+                );
 
                        report.setStatus(Report.PASS);
                }
@@ -123,4 +127,4 @@
 
                return report;
        }
-}
\ No newline at end of file
+}

Deleted: 
/incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/property/PropEvents.java
Url: 
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/property/PropEvents.java?view=auto&rev=109726
==============================================================================

Added: 
incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/property/PropEventsTest.java
Url: 
http://svn.apache.org/viewcvs/incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/property/PropEventsTest.java?view=auto&rev=109727
==============================================================================
--- (empty file)
+++ 
incubator/beehive/trunk/controls/test/src/units/org/apache/beehive/controls/test/java/property/PropEventsTest.java
  Fri Dec  3 12:36:22 2004
@@ -0,0 +1,365 @@
+package org.apache.beehive.controls.test.java.property;
+
+import java.beans.Beans;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyVetoException;
+import java.beans.VetoableChangeListener;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.beehive.test.tools.mantis.annotations.tch.Freq;
+
+import org.apache.beehive.controls.api.bean.ControlBean;
+import org.apache.beehive.controls.test.controls.property.PropEvents;
+import org.apache.beehive.controls.test.controls.property.PropEventsBean;
+
+/**
+ * This test case validates bound and constrained property behaviors, w.r.t. 
to the delivery
+ * of PropertyChange events for bound and constrained events
+ */
[EMAIL PROTECTED]("checkin")
+public class PropEventsTest extends TestCase
+{
+    PropEventsBean eventBean;
+
+    public PropEventsTest( String s ) { super( s ); }
+
+    /**
+     * This base class hold a queue of property change events and makes them 
accessible
+     * for event validation.
+     */
+    abstract static class QueueListener
+    {
+        QueueListener()
+        {
+            initEvents();
+        }
+
+        /**
+         * Resets/initializes the internal event queue
+         */
+        public void initEvents()
+        {
+            eventQueue = new ArrayList<PropertyChangeEvent>();
+        }
+
+        /**
+         * Returns the collection of events
+         */
+        public Collection<PropertyChangeEvent> getEvents() { return 
eventQueue; }
+
+        ArrayList<PropertyChangeEvent> eventQueue;
+    }
+
+    static class ChangeTestListener extends QueueListener 
+                 implements PropEvents.ImplPropertyChange  // + 
java.beans.PropertyChangeListener
+    {
+        /**
+         * Implementation of PropertyChangeListener.propertyChange().  Will 
enqueue
+         * the received event.
+         */
+        public void propertyChange(PropertyChangeEvent pce)
+        {
+            eventQueue.add(pce);
+        }
+    }
+
+    static class VetoableTestListener extends QueueListener
+                 implements PropEvents.ImplVetoableChange  // + 
java.beans.VetoableChangeListener
+    {
+        VetoableTestListener(boolean doVeto)
+        {
+            _doVeto = doVeto;
+        }
+
+        /**
+         * Implementation of PropertyChangeListener.propertyChange().  Will 
enqueue
+         * the received event.
+         */
+        public void vetoableChange(PropertyChangeEvent pce) throws 
PropertyVetoException
+        {
+            eventQueue.add(pce);
+
+            // Veto attempts to set even values
+            if (_doVeto && (((Integer)pce.getNewValue()).intValue() & 1) == 0)
+                throw new PropertyVetoException("Sorry", pce);
+        }
+
+        boolean _doVeto;
+    }
+
+    public void setUp() throws Exception
+    { 
+        eventBean = (PropEventsBean)
+                
Beans.instantiate(Thread.currentThread().getContextClassLoader(),
+                    
"org.apache.beehive.controls.test.controls.property.PropEventsBean");
+    }
+
+    private void validatePropertyEvents(Collection<PropertyChangeEvent> events)
+    {
+        // Now validate the received properties
+        int i = 0;
+        for (PropertyChangeEvent pce : events)
+        {
+            if (pce.getSource() != eventBean)
+                fail("Invalid source value in PropertyChangeEvent");
+
+            if (!pce.getPropertyName().equals("boundInt"))
+                fail("Invalid property name: " + pce.getPropertyName());
+
+            if (!pce.getOldValue().equals(new Integer(i)))
+                fail("Unexpected old value: " + pce.getOldValue() + ", 
expected: " + i);
+
+            if (!pce.getNewValue().equals(new Integer(i+1)))
+                fail("Unexpected new value: " + pce.getNewValue() + ", 
expected: " + (i+1));
+
+            i++;
+        }
+        if (i != 99)
+            fail("Received less events than expected: " + i);
+    }
+
+    /**
+     * Basic test: setting/reading property values by a control client
+     */
+    public void testPropertyChange() throws Exception
+    {
+        // Set the test property to a well-defined initial value
+        eventBean.setBoundInt(0);
+
+        // Create a new test listener and register it on the test bean
+        ChangeTestListener extChange = new ChangeTestListener();
+        eventBean.addPropertyChangeListener(extChange);
+
+        // Create an test listener and register it to indirectly from impl 
callbacks
+        ChangeTestListener implChange = new ChangeTestListener();
+        eventBean.addImplPropertyChangeListener(implChange);
+
+        // Call the bound property setter on the bean 100 times
+        for (int i = 1; i < 100; i++)
+            eventBean.setBoundInt(i);
+
+        // Validate the events received by the external listener
+        validatePropertyEvents(extChange.getEvents());
+
+        // Validate the events received by the implementation via the context
+        validatePropertyEvents(implChange.getEvents());
+
+        // Reset the event queues
+        extChange.initEvents();
+        implChange.initEvents();
+
+        // Change an unbound property and verify that no property change event 
was delivered
+        eventBean.setBasicInt(0);
+        if (extChange.getEvents().size() != 0)
+            fail("Unexpected external event delivered on unbound property 
change");
+        if (implChange.getEvents().size() != 0)
+            fail("Unexpected impl event delivered on unbound property change");
+
+        // Remove the external event listener, change a bound property, and 
verify no event is 
+        // delivered on it, but is delivered to the implentation
+        eventBean.removePropertyChangeListener(extChange);
+        eventBean.setBoundInt(0);
+        if (extChange.getEvents().size() != 0)
+            fail("Unexpected event delivered after listener removed");
+        if (implChange.getEvents().size() == 0)
+            fail("Missing events not delivered after listener removed");
+    }
+
+    /**
+     * Validate the expected set of change and veto events received during the 
testVetoChange
+     * test.  This is factored out so it can be used to validate events 
delivered to both
+     * the implementation and an external listener (which should match)
+     */
+    private void validateVetoEvents(Iterator<PropertyChangeEvent> changeIter,
+                                    Iterator<PropertyChangeEvent> vetoIter)
+    {
+        // Now validate the received properties, there should be one per 
vetoed property,
+        // two per allowed change
+        int i = 1;
+        int expected = 0;
+        boolean expectVeto = false;
+        while(vetoIter.hasNext())
+        {
+            PropertyChangeEvent vce = vetoIter.next();
+
+            expectVeto = (i & 1) == 0;
+
+            if (vce.getSource() != eventBean)
+                fail("Invalid source value in PropertyChangeEvent");
+
+            if (!vce.getPropertyName().equals("constrainedInt"))
+                fail("Invalid property name: " + vce.getPropertyName());
+
+            if (!vce.getOldValue().equals(new Integer(expected)))
+                fail("Unexpected old value: " + vce.getOldValue() + ", 
expected: " + expected);
+
+            if (!vce.getNewValue().equals(new Integer(i)))
+                fail("Unexpected new value: " + vce.getNewValue() + ", 
expected: " + i);
+
+            if (expectVeto)
+            {
+                // If a veto occurred, then there should be a 2nd vetoable 
change event that
+                // goes from the vetoed value back to the last valid value
+                if (!vetoIter.hasNext())
+                    fail("Did not find expected veto revert event");
+                
+                //
+                // Pull the next event, which should revert from the attempted 
change back
+                // to the last accepted value
+                //
+                vce = vetoIter.next();
+                if (vce.getSource() != eventBean)
+                    fail("Invalid source value in PropertyChangeEvent");
+
+                if (!vce.getPropertyName().equals("constrainedInt"))
+                    fail("Invalid property name: " + vce.getPropertyName());
+
+                if (!vce.getOldValue().equals(new Integer(i)))
+                    fail("Unexpected old value: " + vce.getOldValue() + ", 
expected: " + i);
+
+                if (!vce.getNewValue().equals(new Integer(expected)))
+                    fail("Unexpected new value: " + vce.getNewValue() + ", 
expected: " + expected);
+            }
+            else
+            {
+                // Expected to succeed so look for the corresponding 
PropertyChange
+                if (!changeIter.hasNext())
+                    fail("Missing PropertyChange event");
+
+                PropertyChangeEvent pce = changeIter.next();
+                if (pce.getSource() != eventBean)
+                    fail("Invalid source value in PropertyChangeEvent");
+
+                if (!pce.getPropertyName().equals("constrainedInt"))
+                    fail("Invalid property name: " + pce.getPropertyName());
+
+                if (!pce.getOldValue().equals(new Integer(expected)))
+                    fail("Unexpected old value: " + pce.getOldValue() + ", 
expected: " + expected);
+
+                if (!pce.getNewValue().equals(new Integer(i)))
+                    fail("Unexpected new value: " + pce.getNewValue() + ", 
expected: " + i);
+
+                expected = i;
+            }
+
+            i++;
+        }
+        if (expected != 99)
+            fail("Received less events than expected: " + expected);
+    }
+
+    /**
+     * Basic test: setting/reading property values by a control client
+     */
+    public void testVetoChange() throws Exception
+    {
+        // Set the test property to a well-defined initial value
+        eventBean.setConstrainedInt(0);
+
+        // Create a test listener and register it to indirectly receive impl 
callbacks
+        // but not to veto anything
+        VetoableTestListener implVeto = new VetoableTestListener(false);
+        eventBean.addImplVetoableChangeListener(implVeto);
+
+        // Create a test listener and register it as an external listener that 
will veto
+        VetoableTestListener extVeto = new VetoableTestListener(true);
+        eventBean.addVetoableChangeListener(extVeto);
+
+        // Create an test listener and register it to indirectly from impl 
callbacks
+        ChangeTestListener implChange = new ChangeTestListener();
+        eventBean.addImplPropertyChangeListener(implChange);
+
+        // Create an external change listener and register it... this will be 
used to validate the
+        // property changes that were not vetoed
+        ChangeTestListener extChange = new ChangeTestListener();
+        eventBean.addPropertyChangeListener(extChange);
+
+        //
+        // Change the property multiple times, validating that veto exceptions 
propogate as
+        // expected and that the retrieved property value matches the expected 
value (whether
+        // accepted or vetoed)
+        //
+        int expected = 0;
+        for (int i = 1; i < 100; i++)
+        {
+            boolean vetoed = false;
+            boolean expectVeto = (i & 1) == 0;
+            try
+            {
+                eventBean.setConstrainedInt(i);
+            }
+            catch (PropertyVetoException pve)
+            {
+                vetoed = true;
+            }
+
+            if (vetoed)
+            {
+                if (!expectVeto)
+                    fail("Unexpected PropertyVetoException: " + i);
+            }
+            else
+            {
+                if (expectVeto)
+                    fail("Did not receive expected PropertVetoException: " + 
i);
+
+                expected = i;
+            }
+
+            //
+            // Read back the property and see if it was successfully changed 
or vetoed
+            if (eventBean.getConstrainedInt() != expected)
+                fail("Did not get expected value: " + expected + " for " + i);
+        }
+
+        // Validate the events generated on the implementation
+        validateVetoEvents(implChange.getEvents().iterator(), 
implVeto.getEvents().iterator());
+
+        // Validate the events generated on the external listener
+        validateVetoEvents(extChange.getEvents().iterator(), 
extVeto.getEvents().iterator());
+
+        // Reset the event queues
+        extVeto.initEvents();
+        extChange.initEvents();
+        implVeto.initEvents();
+        implChange.initEvents();
+
+        //
+        // Change an unbound property and verify that no property change 
events were delivered
+        //
+        eventBean.setBasicInt(0);
+
+        if (implVeto.getEvents().size() != 0 || implChange.getEvents().size() 
!= 0)
+            fail("Unexpected impl event delivered on unbound property change");
+
+        if (extVeto.getEvents().size() != 0 || extChange.getEvents().size() != 
0)
+            fail("Unexpected external event delivered on unbound property 
change");
+
+        //
+        // Remove the external veto event listener but not the impl veto 
listener change listener, 
+        // change a constrained property, and verify no external veto event is 
delivered but an
+        // impl veto and external change event is delivered
+        //
+        eventBean.removeVetoableChangeListener(extVeto);
+        eventBean.removeImplPropertyChangeListener(implChange);
+        eventBean.setConstrainedInt(1);
+
+        if (extVeto.getEvents().size() != 0)
+            fail("Unexpected external event delivered after listener removed");
+
+        if (implVeto.getEvents().size() == 0) 
+            fail("No impl event delivered after external listener removed");
+
+        if (extChange.getEvents().size() != 1)
+            fail("External change event not delivered after listener removed");
+
+        if (implChange.getEvents().size() != 0)
+            fail("Unexpected Impl change event delivered after listener 
removed");
+    }
+}

Reply via email to